@@ -172,99 +172,251 @@ fu! VHTL_countMatches(string, pattern)
172
172
endwhile
173
173
endfu
174
174
175
+ function ! s: SynAt (l ,c ) " from $VIMRUNTIME/indent/javascript.vim
176
+ let byte = line2byte (a: l ) + a: c - 1
177
+ let pos = index (s: synid_cache [0 ], byte)
178
+ if pos == -1
179
+ let s: synid_cache [:] += [[byte], [synIDattr (synID (a: l , a: c , 0 ), ' name' )]]
180
+ endif
181
+ return s: synid_cache [1 ][pos]
182
+ endfunction
183
+
175
184
if exists (' g:VHTL_debugging' )
176
185
set debug = msg " show errors in indentexpr
186
+ fu ! SynAt (l ,c )
187
+ return s: SynAt (a: l ,a: c )
188
+ endfu
177
189
endif
178
190
fu ! VHTL_debug (str)
179
191
if exists (' g:VHTL_debugging' )
180
192
echom a: str
181
193
endif
182
194
endfu
183
195
196
+ let s: StateClass= {}
197
+ fu ! s: StateClass .new ()
198
+ let l: instance = copy (self )
199
+ let l: instance .currLine = v: lnum
200
+ let l: instance .prevLine = prevnonblank (v: lnum - 1 )
201
+ let l: instance .currSynstack = VHTL_SynSOL (l: instance .currLine)
202
+ let l: instance .prevSynstack = VHTL_SynEOL (l: instance .prevLine)
203
+ return l: instance
204
+ endfu
205
+
206
+ fu ! s: StateClass .startsWithTemplateClose () dict
207
+ return (getline (self .currSynstack)) = ~# ' ^\s*`'
208
+ endfu
209
+
210
+ fu ! s: StateClass .closedJsExpression () dict
211
+ return VHTL_closesJsExpression (getline (self .prevLine))
212
+ endfu
213
+ fu ! s: StateClass .closesJsExpression () dict
214
+ return VHTL_closesJsExpression (getline (self .currLine))
215
+ endfu
216
+ fu ! s: StateClass .openedJsExpression () dict
217
+ return (VHTL_getBracketDepthChange (getline (self .prevLine)) > 0 )
218
+ endfu
219
+ fu ! s: StateClass .opensLitHtmlTemplate () dict
220
+ return VHTL_opensTemplate (getline (self .currLine))
221
+ endfu
222
+ fu ! s: StateClass .openedLitHtmlTemplate () dict
223
+ return VHTL_opensTemplate (getline (self .prevLine))
224
+ endfu
225
+ fu ! s: StateClass .closesLitHtmlTemplate () dict
226
+ return VHTL_closesTemplate (getline (self .currLine))
227
+ endfu
228
+ fu ! s: StateClass .closedLitHtmlTemplate () dict
229
+ return VHTL_closesTemplate (getline (self .prevLine))
230
+ endfu
231
+
232
+ fu ! s: StateClass .isInsideLitHtml () dict
233
+ return VHTL_isSynstackInsideLitHtml (self .currSynstack)
234
+ endfu
235
+ fu ! s: StateClass .wasInsideLitHtml () dict
236
+ return VHTL_isSynstackInsideLitHtml (self .prevSynstack)
237
+ endfu
238
+ fu ! s: StateClass .isInsideJsx () dict
239
+ return IsSynstackInsideJsx (self .currSynstack)
240
+ endfu
241
+
242
+ fu ! s: StateClass .wasHtml () dict
243
+ return get (self .prevSynstack, -1 ) = ~# ' ^html'
244
+ endfu
245
+ fu ! s: StateClass .isHtml () dict
246
+ return get (self .currSynstack, -1 ) = ~# ' ^html'
247
+ endfu
248
+ fu ! s: StateClass .isLitHtmlRegionCloser () dict
249
+ return get (self .currSynstack, -1 ) == # ' litHtmlRegion' && getline (self .currLine) = ~# ' ^\s*`'
250
+ endfu
251
+ fu ! s: StateClass .wasJs () dict
252
+ return get (self .prevSynstack, -1 ) = ~# ' ^js'
253
+ endfu
254
+ fu ! s: StateClass .isJsTemplateBrace () dict
255
+ return get (self .currSynstack, -1 ) == # ' jsTemplateBraces'
256
+ endfu
257
+ fu ! s: StateClass .wasJsTemplateBrace () dict
258
+ return get (self .prevSynstack, -1 ) == # ' jsTemplateBraces'
259
+ endfu
260
+ fu ! s: StateClass .isJs () dict
261
+ return get (self .currSynstack, -1 ) = ~# ' ^js'
262
+ endfu
263
+ fu ! s: StateClass .wasCss () dict
264
+ return get (self .prevSynstack, -1 ) = ~# ' ^css'
265
+ endfu
266
+ fu ! s: StateClass .isCss () dict
267
+ return get (self .currSynstack, -1 ) = ~# ' ^css'
268
+ endfu
269
+
270
+ fu ! s: StateClass .toStr () dict
271
+ return ' {line ' . self .currLine . ' }'
272
+ endfu
273
+
274
+ fu ! s: SkipFuncJsTemplateBraces ()
275
+ " let l:char = getline(line('.'))[col('.')-1]
276
+ let l: syntax = s: SynAt (line (' .' ), col (' .' ))
277
+ if (l: syntax != ' jsTemplateBraces' )
278
+ return 1
279
+ endif
280
+ endfu
281
+
282
+ fu ! s: SkipFuncLitHtmlRegion ()
283
+ " let l:char = getline(line('.'))[col('.')-1]
284
+ let l: syntax = s: SynAt (line (' .' ), col (' .' ))
285
+ if (l: syntax != ' litHtmlRegion' )
286
+ return 1
287
+ endif
288
+ endfu
289
+
290
+ fu ! s: getCloseWordsLeftToRight (lineNum)
291
+ let l: line = getline (a: lineNum )
292
+
293
+ " The following regex converts a line to purely a list of closing words.
294
+ " Pretty cool but not useful
295
+ " echo split(getline(62), '.\{-}\ze\(}\|`\|<\/\w\+>\)')
296
+
297
+ let l: anyCloserWord = ' }\|`\|<\/\w\+>'
298
+
299
+
300
+ let l: index = 0
301
+ let l: closeWords = []
302
+ while v: true
303
+ let [l: term , l: index , l: trash ] = matchstrpos (l: line , l: anyCloserWord , l: index )
304
+ if (l: index == -1 )
305
+ break
306
+ else
307
+ let l: col = l: index + 1
308
+ call add (l: closeWords , [l: term , l: col ])
309
+ endif
310
+ let l: index += 1
311
+ endwhile
312
+ return l: closeWords
313
+ endfu
314
+
315
+ fu ! s: StateClass .getIndentDelta () dict
316
+ let l: closeWords = s: getCloseWordsLeftToRight (self .currLine)
317
+ if len (l: closeWords ) == 0
318
+ return 0
319
+ endif
320
+ let [l: closeWord , l: col ] = l: closeWords [0 ]
321
+ let l: syntax = s: SynAt (self .currLine, l: col )
322
+ if (l: syntax == ' htmlEndTag' )
323
+ call VHTL_debug (' indent_delta: html end tag' )
324
+ return - &shiftwidth
325
+ endif
326
+ if (l: syntax == ' litHtmlRegion' && ' html`' != strpart (getline (self .currLine), l: col- 5 , len (' html`' )))
327
+ call VHTL_debug (' indent_delta: end of litHtmlRegion' )
328
+ return - &shiftwidth
329
+ endif
330
+ return 0
331
+ endfu
332
+
333
+ " html tag, html template, or js expression on previous line
334
+ fu ! s: StateClass .getIndentOfLastClose () dict
335
+
336
+ let l: closeWords = s: getCloseWordsLeftToRight (self .prevLine)
337
+
338
+ if (len (l: closeWords ) == 0 )
339
+ return -1
340
+ endif
341
+
342
+ for l: item in reverse (l: closeWords )
343
+ let [l: closeWord , l: col ] = l: item
344
+ let l: syntax = s: SynAt (self .prevLine, l: col )
345
+ call cursor (self .prevLine, l: col ) " sets start point for searchpair()
346
+ redraw
347
+ if (" }" == l: closeWord && l: syntax == ' jsTemplateBraces' )
348
+ call searchpair (' {' , ' ' , ' }' , ' b' , ' s:SkipFuncJsTemplateBraces()' )
349
+ call VHTL_debug (' js brace base indent' )
350
+ elseif (" `" == l: closeWord && l: syntax == ' litHtmlRegion' )
351
+ call searchpair (' html`' , ' ' , ' \(html\)\@<!`' , ' b' , ' s:SkipFuncLitHtmlRegion()' )
352
+ call VHTL_debug (' lit html region base indent ' )
353
+ elseif (l: syntax == ' htmlEndTag' )
354
+ let l: openWord = substitute (substitute (l: closeWord , ' /' , ' ' , ' ' ), ' >' , ' ' , ' ' )
355
+ call searchpair (l: openWord , ' ' , l: closeWord , ' b' )
356
+ call VHTL_debug (' html tag region base indent ' )
357
+ else
358
+ call VHTL_debug (" UNRECOGNIZED CLOSER SYNTAX: '" . l: syntax . " '" )
359
+ endif
360
+ return indent (line (' .' )) " cursor was moved by searchpair()
361
+ endfor
362
+ endfu
363
+
364
+ " com! MyTest exec "call s:StateClass.new().getIndentOfLastClose()"
365
+
184
366
" Dispatch to indent method for js/html (use custom rules for transitions
185
367
" between syntaxes)
186
368
fu ! ComputeLitHtmlIndent ()
369
+ let s: synid_cache = [[],[]]
370
+
371
+ let l: state = s: StateClass .new ()
187
372
188
373
" get most recent non-empty line
189
374
let l: prev_lnum = prevnonblank (v: lnum - 1 )
190
375
191
376
let l: currLineSynstack = VHTL_SynSOL (v: lnum )
192
377
let l: prevLineSynstack = VHTL_SynEOL (l: prev_lnum )
193
378
194
- if (! VHTL_isSynstackInsideLitHtml (l: currLineSynstack ) && ! VHTL_isSynstackInsideLitHtml (l: prevLineSynstack ))
195
- call VHTL_debug (' outside of litHtmlRegion' )
379
+ if (! l: state .isInsideLitHtml () && ! l: state .wasInsideLitHtml ())
380
+ call VHTL_debug (' outside of litHtmlRegion: ' . b: litHtmlOriginalIndentExpression )
381
+
382
+ if (exists (' b:hi_indent' ) && has_key (b: hi_indent , ' blocklnr' ))
383
+ call remove (b: hi_indent , ' blocklnr' )
384
+ " This avoids a really weird behavior when indenting first line inside
385
+ " style tag and then indenting any normal javascript outside of
386
+ " lit-html region. 'blocklnr' is assigned to line number of <style>,
387
+ " which is then assigned to 'nest' inside vim-javascript's indent code.
388
+ endif
196
389
return eval (b: litHtmlOriginalIndentExpression )
197
390
endif
198
391
199
-
200
- let l: wasCss = (IsSynstackCss (l: prevLineSynstack ))
201
-
202
- " We add an extra dedent for closing } brackets, as long as the matching {
203
- " opener is not on the same line as an opening html`.
204
- "
205
- " This algorithm does not always work and must be rewritten (hopefully to
206
- " something simpler)
207
- let l: adjustForClosingBracket = 0
208
- " if (!l:wasCss && VHTL_closesJsExpression(getline(l:prev_lnum)))
209
- " :exec 'normal! ' . l:prev_lnum . 'G0[{'
210
- " let l:lineWithOpenBracket = getline(line('.'))
211
- " if (!VHTL_opensTemplate(l:lineWithOpenBracket))
212
- " call VHTL_debug('adjusting for close bracket')
213
- " let l:adjustForClosingBracket = - &shiftwidth
214
- " endif
215
- " endif
216
-
217
- let l: wasHtml = (IsSynstackHtml (l: prevLineSynstack ))
218
- let l: isHtml = (IsSynstackHtml (l: currLineSynstack ))
219
- let l: wasCss = (IsSynstackCss (l: prevLineSynstack ))
220
- let l: isCss = (IsSynstackCss (l: currLineSynstack ))
221
- let l: wasJs = (IsSynstackJs (l: prevLineSynstack ))
222
- let l: isJs = (IsSynstackJs (l: currLineSynstack ))
223
-
224
- " If a line starts with template close, it is dedented. If a line otherwise
225
- " contains a template close, the NEXT line is dedented. Note that template
226
- " closers can be balanced out by template openers.
227
- if (VHTL_startsWithTemplateEnd (v: lnum ))
228
- call VHTL_debug (' closed template at start ' )
229
- let l: result = indent (l: prev_lnum ) - &shiftwidth
230
- if (VHTL_closesJsExpression (getline (l: prev_lnum )))
231
- call VHTL_debug (' closed template at start and js expression' )
232
- let l: result -= &shiftwidth
233
- endif
234
- return l: result
392
+ if (l: state .openedLitHtmlTemplate ())
393
+ call VHTL_debug (' opened tagged template literal' )
394
+ return indent (l: prev_lnum ) + &shiftwidth
235
395
endif
236
- if (VHTL_opensTemplate (getline (l: prev_lnum )))
237
- call VHTL_debug (' opened template' )
396
+
397
+ if (l: state .openedJsExpression ())
398
+ call VHTL_debug (' opened js expression' )
238
399
return indent (l: prev_lnum ) + &shiftwidth
239
- elseif (VHTL_closesTemplate (getline (l: prev_lnum )) && ! VHTL_startsWithTemplateEnd (l: prev_lnum ))
240
- call VHTL_debug (' closed template ' . l: adjustForClosingBracket )
241
- let l: result = indent (l: prev_lnum ) - &shiftwidth + l: adjustForClosingBracket
242
- if (VHTL_closesTag (getline (v: lnum )))
243
- call VHTL_debug (' closed template and tag ' . l: adjustForClosingBracket )
244
- let l: result -= &shiftwidth
245
- endif
246
- return l: result
247
- elseif (l: isHtml && l: wasJs && VHTL_closesJsExpression (getline (l: prev_lnum )))
248
- let l: result = indent (l: prev_lnum ) - &shiftwidth
249
- call VHTL_debug (' closes expression' )
250
- if (VHTL_closesTag (getline (v: lnum )))
251
- let l: result -= &shiftwidth
252
- call VHTL_debug (' closes expression and tag' )
253
- endif
254
- return l: result
255
400
endif
256
401
257
- let l: isJsx = (IsSynstackInsideJsx (l: currLineSynstack ))
258
- if (l: wasCss || l: isCss || l: wasHtml || l: isHtml ) && ! l: isJsx
259
- call VHTL_debug (' html indent ' . l: adjustForClosingBracket )
260
- return HtmlIndent () + l: adjustForClosingBracket
402
+ if (l: state .wasJsTemplateBrace () || l: state .isLitHtmlRegionCloser ())
403
+ " let l:indent_basis = previous matching js or template start
404
+ " let l:indent_delta = -1 for starting with closing tag, template, or expression
405
+ let l: indent_basis = l: state .getIndentOfLastClose ()
406
+ if (l: indent_basis == -1 )
407
+ call VHTL_debug (" default to html indent because base indent not found" )
408
+ return HtmlIndent ()
409
+ endif
410
+ let l: indent_delta = l: state .getIndentDelta ()
411
+ call VHTL_debug (' indent delta ' . l: indent_delta )
412
+ call VHTL_debug (' indent basis ' . l: indent_basis )
413
+ return l: indent_basis + l: indent_delta
261
414
endif
262
415
263
- if len (b: litHtmlOriginalIndentExpression )
264
- call VHTL_debug (' js indent ' . b: litHtmlOriginalIndentExpression )
416
+ if ((l: state .wasJs () && ! l: state .wasJsTemplateBrace ()) && (l: state .isJs () && ! l: state .isJsTemplateBrace ()))
265
417
return eval (b: litHtmlOriginalIndentExpression )
266
- else
267
- call VHTL_debug (' cindent should never happen' )
268
- return cindent (v: lnum )
269
418
endif
419
+
420
+ call VHTL_debug (' default to html indent' )
421
+ return HtmlIndent ()
270
422
endfu
0 commit comments