@@ -66,6 +66,24 @@ export class PowerShellNotebooksFeature extends LanguageClientConsumer {
66
66
}
67
67
}
68
68
69
+ interface IPowerShellNotebookCellMetadata {
70
+ commentType : CommentType ;
71
+ openBlockCommentOnOwnLine ?: boolean ;
72
+ closeBlockCommentOnOwnLine ?: boolean ;
73
+ }
74
+
75
+ function CreateCell ( cellKind : vscode . CellKind , source : string [ ] , metadata : IPowerShellNotebookCellMetadata ) : vscode . NotebookCellData {
76
+ return {
77
+ cellKind,
78
+ language : cellKind === vscode . CellKind . Markdown ? "markdown" : "powershell" ,
79
+ outputs : [ ] ,
80
+ source : source . join ( "\n" ) ,
81
+ metadata : {
82
+ custom : metadata ,
83
+ } ,
84
+ } ;
85
+ }
86
+
69
87
class PowerShellNotebookContentProvider implements vscode . NotebookContentProvider {
70
88
private _onDidChangeNotebook = new vscode . EventEmitter < vscode . NotebookDocumentEditEvent > ( ) ;
71
89
public onDidChangeNotebook : vscode . Event < vscode . NotebookDocumentEditEvent > = this . _onDidChangeNotebook . event ;
@@ -79,40 +97,72 @@ class PowerShellNotebookContentProvider implements vscode.NotebookContentProvide
79
97
this . logger . writeDiagnostic ( `Opening Notebook: ${ uri . toString ( ) } ` ) ;
80
98
81
99
const data = ( await vscode . workspace . fs . readFile ( actualUri ) ) . toString ( ) ;
82
- const lines = data . split ( / \r \n | \r | \n / g) ;
100
+
101
+ let lines : string [ ] ;
102
+ // store the line ending in the metadata of the document
103
+ // so that we honor the line ending of the original file
104
+ // on save.
105
+ let lineEnding : string ;
106
+ if ( data . indexOf ( '\r\n' ) !== - 1 ) {
107
+ lines = data . split ( / \r \n / g) ;
108
+ lineEnding = '\r\n' ;
109
+ } else {
110
+ lines = data . split ( / \n / g) ;
111
+ lineEnding = '\n' ;
112
+ }
83
113
84
114
const notebookData : vscode . NotebookData = {
85
115
languages : [ "powershell" ] ,
86
116
cells : [ ] ,
87
- metadata : { }
117
+ metadata : {
118
+ custom : {
119
+ lineEnding,
120
+ }
121
+ }
88
122
} ;
89
123
90
124
let currentCellSource : string [ ] = [ ] ;
91
125
let cellKind : vscode . CellKind | undefined ;
92
126
let insideBlockComment : boolean = false ;
93
127
128
+ // This dictates whether the BlockComment cell was read in with content on the same
129
+ // line as the opening <#. This is so we can preserve the format of the backing file on save.
130
+ let openBlockCommentOnOwnLine : boolean = false ;
131
+
94
132
// Iterate through all lines in a document (aka ps1 file) and group the lines
95
133
// into cells (markdown or code) that will be rendered in Notebook mode.
96
134
// tslint:disable-next-line: prefer-for-of
97
135
for ( let i = 0 ; i < lines . length ; i ++ ) {
98
136
// Handle block comments
99
137
if ( insideBlockComment ) {
100
- if ( lines [ i ] === "#>" ) {
138
+ if ( lines [ i ] . endsWith ( "#>" ) ) {
139
+ // Get the content of the current line without #>
140
+ const currentLine = lines [ i ]
141
+ . substring ( 0 , lines [ i ] . length - 2 )
142
+ . trimRight ( ) ;
143
+
144
+ // This dictates whether the BlockComment cell was read in with content on the same
145
+ // line as the closing #>. This is so we can preserve the format of the backing file
146
+ // on save.
147
+ let closeBlockCommentOnOwnLine : boolean = true ;
148
+ if ( currentLine ) {
149
+ closeBlockCommentOnOwnLine = false ;
150
+ currentCellSource . push ( currentLine ) ;
151
+ }
152
+
101
153
// We've reached the end of a block comment,
102
154
// push a markdown cell.
103
155
insideBlockComment = false ;
104
156
105
- notebookData . cells . push ( {
106
- cellKind : vscode . CellKind . Markdown ,
107
- language : "markdown" ,
108
- outputs : [ ] ,
109
- source : currentCellSource . join ( "\n" ) ,
110
- metadata : {
111
- custom : {
112
- commentType : CommentType . BlockComment
113
- }
157
+ notebookData . cells . push ( CreateCell (
158
+ vscode . CellKind . Markdown ,
159
+ currentCellSource ,
160
+ {
161
+ commentType : CommentType . BlockComment ,
162
+ openBlockCommentOnOwnLine,
163
+ closeBlockCommentOnOwnLine
114
164
}
115
- } ) ;
165
+ ) ) ;
116
166
117
167
currentCellSource = [ ] ;
118
168
cellKind = null ;
@@ -122,29 +172,65 @@ class PowerShellNotebookContentProvider implements vscode.NotebookContentProvide
122
172
// If we're still in a block comment, push the line and continue.
123
173
currentCellSource . push ( lines [ i ] ) ;
124
174
continue ;
125
- } else if ( lines [ i ] === "<#" ) {
175
+ } else if ( lines [ i ] . startsWith ( "<#" ) ) {
126
176
// If we found the start of a block comment,
127
177
// insert what we saw leading up to this.
128
178
// If cellKind is null/undefined, that means we
129
179
// are starting the file with a BlockComment.
130
180
if ( cellKind ) {
131
- notebookData . cells . push ( {
181
+ notebookData . cells . push ( CreateCell (
132
182
cellKind ,
133
- language : cellKind === vscode . CellKind . Markdown ? "markdown" : "powershell" ,
134
- outputs : [ ] ,
135
- source : currentCellSource . join ( "\n" ) ,
136
- metadata : {
137
- custom : {
138
- commentType : cellKind === vscode . CellKind . Markdown ? CommentType . LineComment : CommentType . Disabled ,
139
- }
183
+ currentCellSource ,
184
+ {
185
+ commentType : cellKind === vscode . CellKind . Markdown ? CommentType . LineComment : CommentType . Disabled ,
140
186
}
141
- } ) ;
187
+ ) ) ;
142
188
}
143
189
144
- // reset state because we're starting a new Markdown cell.
145
- currentCellSource = [ ] ;
190
+ // We're starting a new Markdown cell.
146
191
cellKind = vscode . CellKind . Markdown ;
147
192
insideBlockComment = true ;
193
+
194
+ // Get the content of the current line without `<#`
195
+ const currentLine = lines [ i ]
196
+ . substring ( 2 , lines [ i ] . length )
197
+ . trimLeft ( ) ;
198
+
199
+ // If we have additional text on the line with the `<#`
200
+ // We need to keep track of what comes after it.
201
+ if ( currentLine ) {
202
+ // If both the `<#` and the `#>` are on the same line
203
+ // we want to push a markdown cell.
204
+ if ( currentLine . endsWith ( "#>" ) ) {
205
+ // Get the content of the current line without `#>`
206
+ const newCurrentLine = currentLine
207
+ . substring ( 0 , currentLine . length - 2 )
208
+ . trimRight ( ) ;
209
+
210
+ notebookData . cells . push ( CreateCell (
211
+ vscode . CellKind . Markdown ,
212
+ [ newCurrentLine ] ,
213
+ {
214
+ commentType : CommentType . BlockComment ,
215
+ openBlockCommentOnOwnLine : false ,
216
+ closeBlockCommentOnOwnLine : false ,
217
+ }
218
+ ) ) ;
219
+
220
+ // Reset
221
+ currentCellSource = [ ] ;
222
+ cellKind = null ;
223
+ insideBlockComment = false ;
224
+ continue ;
225
+ }
226
+
227
+ openBlockCommentOnOwnLine = false ;
228
+ currentCellSource = [ currentLine ] ;
229
+ } else {
230
+ openBlockCommentOnOwnLine = true ;
231
+ currentCellSource = [ ] ;
232
+ }
233
+
148
234
continue ;
149
235
}
150
236
@@ -158,17 +244,13 @@ class PowerShellNotebookContentProvider implements vscode.NotebookContentProvide
158
244
} else {
159
245
// If cellKind has a value, then we can add the cell we've just computed.
160
246
if ( cellKind ) {
161
- notebookData . cells . push ( {
162
- cellKind : cellKind ! ,
163
- language : cellKind === vscode . CellKind . Markdown ? "markdown" : "powershell" ,
164
- outputs : [ ] ,
165
- source : currentCellSource . join ( "\n" ) ,
166
- metadata : {
167
- custom : {
168
- commentType : cellKind === vscode . CellKind . Markdown ? CommentType . LineComment : CommentType . Disabled ,
169
- }
247
+ notebookData . cells . push ( CreateCell (
248
+ cellKind ,
249
+ currentCellSource ,
250
+ {
251
+ commentType : cellKind === vscode . CellKind . Markdown ? CommentType . LineComment : CommentType . Disabled ,
170
252
}
171
- } ) ;
253
+ ) ) ;
172
254
}
173
255
174
256
// set initial new cell state
@@ -182,17 +264,13 @@ class PowerShellNotebookContentProvider implements vscode.NotebookContentProvide
182
264
// when there is only the _start_ of a block comment but not an _end_.)
183
265
// add the appropriate cell.
184
266
if ( currentCellSource . length ) {
185
- notebookData . cells . push ( {
186
- cellKind : cellKind ! ,
187
- language : cellKind === vscode . CellKind . Markdown ? "markdown" : "powershell" ,
188
- outputs : [ ] ,
189
- source : currentCellSource . join ( "\n" ) ,
190
- metadata : {
191
- custom : {
192
- commentType : cellKind === vscode . CellKind . Markdown ? CommentType . LineComment : CommentType . Disabled ,
193
- }
267
+ notebookData . cells . push ( CreateCell (
268
+ cellKind ! ,
269
+ currentCellSource ,
270
+ {
271
+ commentType : cellKind === vscode . CellKind . Markdown ? CommentType . LineComment : CommentType . Disabled ,
194
272
}
195
- } ) ;
273
+ ) ) ;
196
274
}
197
275
198
276
return notebookData ;
@@ -228,23 +306,37 @@ class PowerShellNotebookContentProvider implements vscode.NotebookContentProvide
228
306
const retArr : string [ ] = [ ] ;
229
307
for ( const cell of document . cells ) {
230
308
if ( cell . cellKind === vscode . CellKind . Code ) {
231
- retArr . push ( ...cell . document . getText ( ) . split ( / \r | \n | \r \n / ) ) ;
309
+ retArr . push ( ...cell . document . getText ( ) . split ( / \r \n | \n / ) ) ;
232
310
} else {
233
311
// First honor the comment type of the cell if it already has one.
234
312
// If not, use the user setting.
235
313
const commentKind = cell . metadata . custom ?. commentType || Settings . load ( ) . notebooks . saveMarkdownCellsAs ;
236
314
237
315
if ( commentKind === CommentType . BlockComment ) {
238
- retArr . push ( "<#" ) ;
239
- retArr . push ( ...cell . document . getText ( ) . split ( / \r | \n | \r \n / ) ) ;
240
- retArr . push ( "#>" ) ;
316
+ const openBlockCommentOnOwnLine : boolean = cell . metadata . custom ?. openBlockCommentOnOwnLine ;
317
+ const closeBlockCommentOnOwnLine : boolean = cell . metadata . custom ?. closeBlockCommentOnOwnLine ;
318
+ const text = cell . document . getText ( ) . split ( / \r \n | \n / ) ;
319
+ if ( openBlockCommentOnOwnLine ) {
320
+ retArr . push ( "<#" ) ;
321
+ } else {
322
+ text [ 0 ] = `<# ${ text [ 0 ] } ` ;
323
+ }
324
+
325
+ if ( ! closeBlockCommentOnOwnLine ) {
326
+ text [ text . length - 1 ] += " #>" ;
327
+ retArr . push ( ...text ) ;
328
+ } else {
329
+ retArr . push ( ...text ) ;
330
+ retArr . push ( "#>" ) ;
331
+ }
241
332
} else {
242
- retArr . push ( ...cell . document . getText ( ) . split ( / \r | \n | \r \n / ) . map ( ( line ) => `# ${ line } ` ) ) ;
333
+ retArr . push ( ...cell . document . getText ( ) . split ( / \r \n | \n / ) . map ( ( line ) => `# ${ line } ` ) ) ;
243
334
}
244
335
}
245
336
}
246
337
247
- await vscode . workspace . fs . writeFile ( targetResource , new TextEncoder ( ) . encode ( retArr . join ( "\n" ) ) ) ;
338
+ const eol = document . metadata . custom . lineEnding ;
339
+ await vscode . workspace . fs . writeFile ( targetResource , new TextEncoder ( ) . encode ( retArr . join ( eol ) ) ) ;
248
340
}
249
341
}
250
342
0 commit comments