@@ -78,7 +78,7 @@ const transpilation_cache: Map<string,ITranspilationResult> = new VolatileMap(18
78
78
/** The resulting coffee must still always be valid and parsable by the compiler,
79
79
and should not shift characters around much (otherwise source maps would need changes too) */
80
80
function preprocess_coffee ( coffee_doc : TextDocument ) {
81
- const tmp = coffee_doc . getText ( )
81
+ const tmp = ( coffee_doc . getText ( ) as string )
82
82
// Enable autocomplete at `@|`. Replace with magic snippet that allows for both @|
83
83
// and standalone @ sign. Cursor needs to be adjusted properly in doComplete().
84
84
// .____CoffeeSenseAtSign is replaced with (this.valueOf(),this) in postprocess_js.
@@ -115,7 +115,32 @@ function preprocess_coffee(coffee_doc: TextDocument) {
115
115
logger . logDebug ( `replace trailing comma inside { } with ↯ ${ coffee_doc . uri } ` )
116
116
return `,↯${ ws } }`
117
117
} )
118
+
118
119
const tmp_lines = tmp . split ( '\n' )
120
+
121
+ const starts_with_block_comment_lines = tmp_lines . map ( ( line ) =>
122
+ line . match ( / ^ \s * # # # ( [ ^ # ] | $ ) / mg)
123
+ ) . map ( ( match , line_i ) =>
124
+ match ? line_i : - 1
125
+ ) . filter ( line_i =>
126
+ line_i > - 1
127
+ ) . map ( ( line_i , i ) =>
128
+ // Eg. if block comment lines were detected and prefixed with a single # line
129
+ // at i=2 and i=4, the array will contain [2,5] so we can iterate and modify
130
+ // arrays from the beginning here and in postprocess_js.
131
+ line_i + i )
132
+
133
+ for ( const line_i of starts_with_block_comment_lines ) {
134
+ // Arrange for block comments to be placed directly before their below line in JS (#1)
135
+ // Inserts extra lines that need to be tracked so the source maps can be adjusted. That's
136
+ // also why this needs to happen before object_tweak_coffee_lines.
137
+ // Couldn't find a solution that does not insert extra lines:
138
+ // - prefix all ### with another "# " -> long block comment sections become code
139
+ // - prefix with backticks: ### -> ``### -> fails inside objects or multiline assignments
140
+ logger . logDebug ( `replace: prefix ### with single # line ${ coffee_doc . uri } ` )
141
+ tmp_lines . splice ( line_i , 0 , '#' )
142
+ }
143
+
119
144
const object_tweak_coffee_lines : number [ ] = [ ]
120
145
tmp_lines . forEach ( ( line , line_i ) => {
121
146
// Enable autocomplete on empty lines inside object properties.
@@ -137,12 +162,14 @@ function preprocess_coffee(coffee_doc: TextDocument) {
137
162
if ( next_textual_line_indentation > empty_line_indentation . length )
138
163
return
139
164
}
165
+ logger . logDebug ( `replace append empty line with 𒐛:𒐛 ${ coffee_doc . uri } ` )
140
166
tmp_lines [ line_i ] = empty_line_indentation + '𒐛:𒐛'
141
167
object_tweak_coffee_lines . push ( line_i )
142
168
}
143
169
} )
144
170
const coffee = tmp_lines . join ( '\n' )
145
- return { coffee, object_tweak_coffee_lines }
171
+ const inserted_coffee_lines = starts_with_block_comment_lines
172
+ return { coffee, inserted_coffee_lines, object_tweak_coffee_lines }
146
173
}
147
174
148
175
/** further transforms that *can break* cs compilation, to be used if compilation could not succeed without it anyway */
@@ -263,7 +290,7 @@ const try_translate_coffee = (coffee_doc: TextDocument): ITranspilationResult =>
263
290
} else {
264
291
fake_line_mechanism = 'coffee_in_js'
265
292
normal_compilation_diagnostics = result . diagnostics
266
-
293
+
267
294
coffee_error_line_no = result . diagnostics ! [ 0 ] ! . range . start . line
268
295
coffee_error_offset = coffee_doc . offsetAt ( Position . create ( coffee_error_line_no , 0 ) )
269
296
const coffee_error_next_newline_position = coffee . slice ( coffee_error_offset ) . indexOf ( '\n' )
@@ -410,7 +437,7 @@ const try_translate_coffee = (coffee_doc: TextDocument): ITranspilationResult =>
410
437
* Applies some transformations to the JS in result and updates source_map accordingly.
411
438
* These transforms do not depend on any previous information.
412
439
*/
413
- function postprocess_js ( result : ITranspilationResult , object_tweak_coffee_lines : number [ ] ) {
440
+ function postprocess_js ( result : ITranspilationResult , object_tweak_coffee_lines : number [ ] , inserted_coffee_lines : number [ ] ) {
414
441
if ( ! result . js || ! result . source_map )
415
442
return
416
443
@@ -442,9 +469,23 @@ function postprocess_js(result: ITranspilationResult, object_tweak_coffee_lines:
442
469
source_map_entry . column = 0
443
470
}
444
471
}
472
+
473
+ let skip_lines_count = inserted_coffee_lines . findIndex ( inserted_line_i =>
474
+ source_map_entry . sourceLine < inserted_line_i )
475
+ if ( skip_lines_count < 0 )
476
+ skip_lines_count = inserted_coffee_lines . length
477
+ source_map_entry . sourceLine -= skip_lines_count
445
478
} )
446
479
} )
447
480
481
+ if ( result . fake_line ) {
482
+ let fake_line_skip_lines_count = inserted_coffee_lines . findIndex ( inserted_line_i =>
483
+ result . fake_line ! < inserted_line_i )
484
+ if ( fake_line_skip_lines_count < 0 )
485
+ fake_line_skip_lines_count = inserted_coffee_lines . length
486
+ result . fake_line -= fake_line_skip_lines_count
487
+ }
488
+
448
489
// console.time('var-decl-fix')
449
490
//////////////////////////////////////
450
491
///////// Modify variable declarations to solve various TS compiler errors:
@@ -461,7 +502,7 @@ function postprocess_js(result: ITranspilationResult, object_tweak_coffee_lines:
461
502
// var a;
462
503
// a = 1;
463
504
// a = 'one';
464
- /////// and now `a` is of type `number | string` (https://github.com/microsoft/TypeScript/issues/45369).
505
+ /////// and now `a` is of type `number | string` (https://github.com/microsoft/TypeScript/issues/45369).
465
506
// Below is a hacky workaround that should fix these issues in most cases. It moves the
466
507
// declaration part (`var`) down to the variable's first implementation position.
467
508
// This works only with easy implementations and single-variable array destructuring:
@@ -592,7 +633,7 @@ const transpile_service: ITranspileService = {
592
633
return cached
593
634
}
594
635
595
- const { coffee : preprocessed_coffee , object_tweak_coffee_lines } = preprocess_coffee ( orig_coffee_doc )
636
+ const { coffee : preprocessed_coffee , object_tweak_coffee_lines, inserted_coffee_lines } = preprocess_coffee ( orig_coffee_doc )
596
637
// As coffee was modified, offsets and positions are changed and for these purposes,
597
638
// we need to construct a new doc
598
639
let mod_coffee_doc = TextDocument . create ( orig_coffee_doc . uri , 'coffeescript' , 1 , preprocessed_coffee )
@@ -605,7 +646,7 @@ const transpile_service: ITranspileService = {
605
646
}
606
647
607
648
if ( result . js && result . source_map ) {
608
- postprocess_js ( result , object_tweak_coffee_lines )
649
+ postprocess_js ( result , object_tweak_coffee_lines , inserted_coffee_lines )
609
650
} else {
610
651
// Nothing worked at all. As a last resort, just pass the coffee to tsserver,
611
652
// with minimal transforms:
@@ -657,7 +698,7 @@ const transpile_service: ITranspileService = {
657
698
line_i ++
658
699
}
659
700
}
660
-
701
+
661
702
if ( mapped )
662
703
coffee_pos = Position . create ( mapped . sourceLine , mapped . sourceColumn )
663
704
else
@@ -714,7 +755,7 @@ const transpile_service: ITranspileService = {
714
755
}
715
756
}
716
757
}
717
-
758
+
718
759
// TODO: revise this function, maybe this should be always all line matches by default instead
719
760
const get_fitting_js_matches = ( ) => {
720
761
const js_matches_by_line = result . source_map !
@@ -805,7 +846,7 @@ const transpile_service: ITranspileService = {
805
846
return abcdefg ( js_matches )
806
847
}
807
848
const js_match = choose_js_match ( )
808
-
849
+
809
850
let line = js_match ?. line
810
851
let column = js_match ?. column
811
852
if ( js_match && line != null && result . fake_line == coffee_position . line && result . fake_line_mechanism === 'coffee_in_js' ) {
0 commit comments