Update runtime files.
This commit is contained in:
314
runtime/autoload/dist/vimindent.vim
vendored
314
runtime/autoload/dist/vimindent.vim
vendored
@ -2,12 +2,12 @@ vim9script
|
||||
|
||||
# Language: Vim script
|
||||
# Maintainer: github user lacygoill
|
||||
# Last Change: 2023 Jan 03
|
||||
# Last Change: 2023 Feb 01
|
||||
|
||||
# NOTE: Whenever you change the code, make sure the tests are still passing:
|
||||
#
|
||||
# $ cd runtime/indent/
|
||||
# $ make clean; make test || vimdiff testdir/vim.{fail,ok}
|
||||
# $ make clean; make test || vimdiff testdir/vim.{ok,fail}
|
||||
|
||||
# Config {{{1
|
||||
|
||||
@ -112,6 +112,10 @@ const DICT_KEY: string = '^\s*\%('
|
||||
.. '\)'
|
||||
.. ':\%(\s\|$\)'
|
||||
|
||||
# NOT_A_DICT_KEY {{{3
|
||||
|
||||
const NOT_A_DICT_KEY: string = ':\@!'
|
||||
|
||||
# END_OF_COMMAND {{{3
|
||||
|
||||
const END_OF_COMMAND: string = $'\s*\%($\|||\@!\|{INLINE_COMMENT}\)'
|
||||
@ -144,19 +148,43 @@ const HEREDOC_OPERATOR: string = '\s=<<\s\@=\%(\s\+\%(trim\|eval\)\)\{,2}'
|
||||
#
|
||||
# But sometimes, it can be too costly and cause `E363` to be given.
|
||||
const PATTERN_DELIMITER: string = '[-+*/%]\%(=\s\)\@!'
|
||||
|
||||
# QUOTE {{{3
|
||||
|
||||
const QUOTE: string = '["'']'
|
||||
# }}}2
|
||||
# Syntaxes {{{2
|
||||
# ASSIGNS_HEREDOC {{{3
|
||||
# BLOCKS {{{3
|
||||
|
||||
const ASSIGNS_HEREDOC: string = $'^\%({COMMENT}\)\@!.*\%({HEREDOC_OPERATOR}\)\s\+\zs[A-Z]\+{END_OF_LINE}'
|
||||
const BLOCKS: list<list<string>> = [
|
||||
['if', 'el\%[se]', 'elseif\=', 'en\%[dif]'],
|
||||
['for', 'endfor\='],
|
||||
['wh\%[ile]', 'endw\%[hile]'],
|
||||
['try', 'cat\%[ch]', 'fina\|finally\=', 'endt\%[ry]'],
|
||||
['def', 'enddef'],
|
||||
['fu\%[nction](\@!', 'endf\%[unction]'],
|
||||
['class', 'endclass'],
|
||||
['interface', 'endinterface'],
|
||||
['enum', 'endenum'],
|
||||
['aug\%[roup]\%(\s\+[eE][nN][dD]\)\@!\s\+\S\+', 'aug\%[roup]\s\+[eE][nN][dD]'],
|
||||
]
|
||||
|
||||
# CD_COMMAND {{{3
|
||||
# MODIFIERS {{{3
|
||||
|
||||
const CD_COMMAND: string = $'\<[lt]\=cd!\=\s\+-{END_OF_COMMAND}'
|
||||
# some keywords can be prefixed by modifiers (e.g. `def` can be prefixed by `export`)
|
||||
const MODIFIERS: dict<string> = {
|
||||
def: ['export', 'static'],
|
||||
class: ['export', 'abstract', 'export abstract'],
|
||||
interface: ['export'],
|
||||
}
|
||||
# ...
|
||||
# class: ['export', 'abstract', 'export abstract'],
|
||||
# ...
|
||||
# →
|
||||
# ...
|
||||
# class: '\%(export\|abstract\|export\s\+abstract\)\s\+',
|
||||
# ...
|
||||
->map((_, mods: list<string>): string =>
|
||||
'\%(' .. mods
|
||||
->join('\|')
|
||||
->substitute('\s\+', '\\s\\+', 'g')
|
||||
.. '\)' .. '\s\+')
|
||||
|
||||
# HIGHER_ORDER_COMMAND {{{3
|
||||
|
||||
@ -174,58 +202,102 @@ patterns =<< trim eval END
|
||||
g\%[lobal]!\={PATTERN_DELIMITER}.*
|
||||
v\%[global]!\={PATTERN_DELIMITER}.*
|
||||
END
|
||||
const HIGHER_ORDER_COMMAND: string = $'\%(^\|{BAR_SEPARATION}\)\s*\<\%(' .. patterns->join('\|') .. '\):\@!'
|
||||
|
||||
# MAPPING_COMMAND {{{3
|
||||
const HIGHER_ORDER_COMMAND: string = $'\%(^\|{BAR_SEPARATION}\)\s*\<\%({patterns->join('\|')}\){NOT_A_DICT_KEY}'
|
||||
|
||||
const MAPPING_COMMAND: string = '\%(\<sil\%[ent]!\=\s\+\)\=\<[nvxsoilct]\=\%(nore\|un\)map!\=\s'
|
||||
# START_MIDDLE_END {{{3
|
||||
|
||||
# NORMAL_COMMAND {{{3
|
||||
# Let's derive this constant from `BLOCKS`:
|
||||
#
|
||||
# [['if', 'el\%[se]', 'elseif\=', 'en\%[dif]'],
|
||||
# ['for', 'endfor\='],
|
||||
# ...,
|
||||
# [...]]
|
||||
# →
|
||||
# {
|
||||
# 'for': ['for', '', 'endfor\='],
|
||||
# 'endfor': ['for', '', 'endfor\='],
|
||||
# 'if': ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
# 'else': ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
# 'elseif': ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
# 'endif': ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
# ...
|
||||
# }
|
||||
var START_MIDDLE_END: dict<list<string>>
|
||||
|
||||
const NORMAL_COMMAND: string = '\<norm\%[al]!\=\s*\S\+$'
|
||||
def Unshorten(kwd: string): string
|
||||
return BlockStartKeyword(kwd)
|
||||
enddef
|
||||
|
||||
# PLUS_MINUS_COMMAND {{{3
|
||||
def BlockStartKeyword(line: string): string
|
||||
var kwd: string = line->matchstr('\l\+')
|
||||
return fullcommand(kwd, false)
|
||||
enddef
|
||||
|
||||
# In legacy, the `:+` and `:-` commands are not required to be preceded by a colon.
|
||||
# As a result, when `+` or `-` is alone on a line, there is ambiguity.
|
||||
# It might be an operator or a command.
|
||||
# To not break the indentation in legacy scripts, we might need to consider such
|
||||
# lines as commands.
|
||||
const PLUS_MINUS_COMMAND: string = '^\s*[+-]\s*$'
|
||||
{
|
||||
for kwds: list<string> in BLOCKS
|
||||
var [start: string, middle: string, end: string] = [kwds[0], '', kwds[-1]]
|
||||
if MODIFIERS->has_key(start->Unshorten())
|
||||
start = $'\%({MODIFIERS[start]}\)\={start}'
|
||||
endif
|
||||
if kwds->len() > 2
|
||||
middle = kwds[1 : -2]->join('\|')
|
||||
endif
|
||||
for kwd: string in kwds
|
||||
START_MIDDLE_END->extend({[kwd->Unshorten()]: [start, middle, end]})
|
||||
endfor
|
||||
endfor
|
||||
}
|
||||
|
||||
START_MIDDLE_END = START_MIDDLE_END
|
||||
->map((_, kwds: list<string>) =>
|
||||
kwds->map((_, kwd: string) => kwd == ''
|
||||
? ''
|
||||
: $'\%(^\|{BAR_SEPARATION}\|\<sil\%[ent]\|{HIGHER_ORDER_COMMAND}\)\s*'
|
||||
.. $'\<\%({kwd}\)\>\%(\s*{OPERATOR}\)\@!'))
|
||||
|
||||
lockvar! START_MIDDLE_END
|
||||
|
||||
# ENDS_BLOCK {{{3
|
||||
|
||||
const ENDS_BLOCK: string = '^\s*\%('
|
||||
.. 'en\%[dif]'
|
||||
.. '\|' .. 'endfor\='
|
||||
.. '\|' .. 'endw\%[hile]'
|
||||
.. '\|' .. 'endt\%[ry]'
|
||||
.. '\|' .. 'enddef'
|
||||
.. '\|' .. 'endclass'
|
||||
.. '\|' .. 'endf\%[unction]'
|
||||
.. '\|' .. 'aug\%[roup]\s\+[eE][nN][dD]'
|
||||
.. BLOCKS
|
||||
->copy()
|
||||
->map((_, kwds: list<string>): string => kwds[-1])
|
||||
->join('\|')
|
||||
.. '\|' .. CLOSING_BRACKET
|
||||
.. $'\){END_OF_COMMAND}'
|
||||
|
||||
# ENDS_BLOCK_OR_CLAUSE {{{3
|
||||
|
||||
patterns =<< trim END
|
||||
en\%[dif]
|
||||
el\%[se]
|
||||
endfor\=
|
||||
endclass
|
||||
endw\%[hile]
|
||||
endt\%[ry]
|
||||
fina\|finally\=
|
||||
enddef
|
||||
endf\%[unction]
|
||||
aug\%[roup]\s\+[eE][nN][dD]
|
||||
END
|
||||
patterns = BLOCKS
|
||||
->copy()
|
||||
->map((_, kwds: list<string>) => kwds[1 :])
|
||||
->flattennew()
|
||||
# `catch` and `elseif` need to be handled as special cases
|
||||
->filter((_, pat: string): bool => pat->Unshorten() !~ '^\%(catch\|elseif\)\>')
|
||||
|
||||
const ENDS_BLOCK_OR_CLAUSE: string = '^\s*\%(' .. patterns->join('\|') .. $'\){END_OF_COMMAND}'
|
||||
.. $'\|^\s*cat\%[ch]\%(\s\+\({PATTERN_DELIMITER}\).*\1\)\={END_OF_COMMAND}'
|
||||
.. $'\|^\s*elseif\=\>\%({OPERATOR}\)\@!'
|
||||
|
||||
# STARTS_NAMED_BLOCK {{{3
|
||||
|
||||
patterns = []
|
||||
{
|
||||
for kwds: list<string> in BLOCKS
|
||||
for kwd: string in kwds[0 : -2]
|
||||
if MODIFIERS->has_key(kwd->Unshorten())
|
||||
patterns += [$'\%({MODIFIERS[kwd]}\)\={kwd}']
|
||||
else
|
||||
patterns += [kwd]
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
}
|
||||
|
||||
const STARTS_NAMED_BLOCK: string = $'^\s*\%(sil\%[ent]\s\+\)\=\%({patterns->join('\|')}\)\>{NOT_A_DICT_KEY}'
|
||||
|
||||
# STARTS_CURLY_BLOCK {{{3
|
||||
|
||||
# TODO: `{` alone on a line is not necessarily the start of a block.
|
||||
@ -238,73 +310,57 @@ const STARTS_CURLY_BLOCK: string = '\%('
|
||||
.. '\|' .. $'^\%(\s*\|.*{BAR_SEPARATION}\s*\)\%(com\%[mand]\|au\%[tocmd]\).*\zs\s{{'
|
||||
.. '\)' .. END_OF_COMMAND
|
||||
|
||||
# STARTS_NAMED_BLOCK {{{3
|
||||
|
||||
# All of these will be used at the start of a line (or after a bar).
|
||||
# NOTE: Don't replace `\%x28` with `(`.{{{
|
||||
#
|
||||
# Otherwise, the paren would be unbalanced which might cause syntax highlighting
|
||||
# issues much later in the code of the current script (sometimes, the syntax
|
||||
# highlighting plugin fails to correctly recognize a heredoc which is far away
|
||||
# and/or not displayed because inside a fold).
|
||||
# }}}
|
||||
patterns =<< trim END
|
||||
if
|
||||
el\%[se]
|
||||
elseif\=
|
||||
for
|
||||
class
|
||||
wh\%[ile]
|
||||
try
|
||||
cat\%[ch]
|
||||
fina\|finally\=
|
||||
fu\%[nction]\%x28\@!
|
||||
\%(export\s\+\)\=def
|
||||
aug\%[roup]\%(\s\+[eE][nN][dD]\)\@!\s\+\S\+
|
||||
END
|
||||
const STARTS_NAMED_BLOCK: string = '^\s*\%(sil\%[ent]\s\+\)\=\%(' .. patterns->join('\|') .. '\)\>:\@!'
|
||||
|
||||
# STARTS_FUNCTION {{{3
|
||||
|
||||
const STARTS_FUNCTION: string = '^\s*\%(export\s\+\)\=def\>:\@!'
|
||||
const STARTS_FUNCTION: string = $'^\s*\%({MODIFIERS.def}\)\=def\>{NOT_A_DICT_KEY}'
|
||||
|
||||
# ENDS_FUNCTION {{{3
|
||||
|
||||
const ENDS_FUNCTION: string = $'^\s*enddef\>:\@!{END_OF_COMMAND}'
|
||||
const ENDS_FUNCTION: string = $'^\s*enddef\>{END_OF_COMMAND}'
|
||||
|
||||
# START_MIDDLE_END {{{3
|
||||
# ASSIGNS_HEREDOC {{{3
|
||||
|
||||
const START_MIDDLE_END: dict<list<string>> = {
|
||||
if: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
else: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
elseif: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
endif: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
|
||||
for: ['for', '', 'endfor\='],
|
||||
endfor: ['for', '', 'endfor\='],
|
||||
class: ['class', '', 'endclass'],
|
||||
endclass: ['class', '', 'endclass'],
|
||||
while: ['wh\%[ile]', '', 'endw\%[hile]'],
|
||||
endwhile: ['wh\%[ile]', '', 'endw\%[hile]'],
|
||||
try: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
|
||||
catch: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
|
||||
finally: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
|
||||
endtry: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
|
||||
def: ['\%(export\s\+\)\=def', '', 'enddef'],
|
||||
enddef: ['\%(export\s\+\)\=def', '', 'enddef'],
|
||||
function: ['fu\%[nction]', '', 'endf\%[unction]'],
|
||||
endfunction: ['fu\%[nction]', '', 'endf\%[unction]'],
|
||||
augroup: ['aug\%[roup]\%(\s\+[eE][nN][dD]\)\@!\s\+\S\+', '', 'aug\%[roup]\s\+[eE][nN][dD]'],
|
||||
}->map((_, kwds: list<string>) =>
|
||||
kwds->map((_, kwd: string) => kwd == ''
|
||||
? ''
|
||||
: $'\%(^\|{BAR_SEPARATION}\|\<sil\%[ent]\|{HIGHER_ORDER_COMMAND}\)\s*'
|
||||
.. $'\%({printf('\C\<\%%(%s\)\>:\@!\%%(\s*%s\)\@!', kwd, OPERATOR)}\)'))
|
||||
const ASSIGNS_HEREDOC: string = $'^\%({COMMENT}\)\@!.*\%({HEREDOC_OPERATOR}\)\s\+\zs[A-Z]\+{END_OF_LINE}'
|
||||
|
||||
# PLUS_MINUS_COMMAND {{{3
|
||||
|
||||
# In legacy, the `:+` and `:-` commands are not required to be preceded by a colon.
|
||||
# As a result, when `+` or `-` is alone on a line, there is ambiguity.
|
||||
# It might be an operator or a command.
|
||||
# To not break the indentation in legacy scripts, we might need to consider such
|
||||
# lines as commands.
|
||||
const PLUS_MINUS_COMMAND: string = '^\s*[+-]\s*$'
|
||||
|
||||
# TRICKY_COMMANDS {{{3
|
||||
|
||||
# Some commands are tricky because they accept an argument which can be
|
||||
# conflated with an operator. Examples:
|
||||
#
|
||||
# argdelete *
|
||||
# cd -
|
||||
# normal! ==
|
||||
# nunmap <buffer> (
|
||||
#
|
||||
# TODO: Other commands might accept operators as argument. Handle them too.
|
||||
patterns =<< trim eval END
|
||||
{'\'}<argd\%[elete]\s\+\*\s*$
|
||||
\<[lt]\=cd!\=\s\+-\s*$
|
||||
\<norm\%[al]!\=\s*\S\+$
|
||||
\%(\<sil\%[ent]!\=\s\+\)\=\<[nvxsoilct]\=\%(nore\|un\)map!\=\s
|
||||
{PLUS_MINUS_COMMAND}
|
||||
END
|
||||
|
||||
const TRICKY_COMMANDS: string = patterns->join('\|')
|
||||
# }}}2
|
||||
# EOL {{{2
|
||||
# OPENING_BRACKET_AT_EOL {{{3
|
||||
|
||||
const OPENING_BRACKET_AT_EOL: string = OPENING_BRACKET .. END_OF_VIM9_LINE
|
||||
|
||||
# CLOSING_BRACKET_AT_EOL {{{3
|
||||
|
||||
const CLOSING_BRACKET_AT_EOL: string = CLOSING_BRACKET .. END_OF_VIM9_LINE
|
||||
|
||||
# COMMA_AT_EOL {{{3
|
||||
|
||||
const COMMA_AT_EOL: string = $',{END_OF_VIM9_LINE}'
|
||||
@ -392,6 +448,7 @@ export def Expr(lnum = v:lnum): number # {{{2
|
||||
endif
|
||||
|
||||
if line_A->AtStartOf('FuncHeader')
|
||||
&& !IsInInterface()
|
||||
line_A.lnum->CacheFuncHeader()
|
||||
elseif line_A.lnum->IsInside('FuncHeader')
|
||||
return b:vimindent.startindent + 2 * shiftwidth()
|
||||
@ -430,6 +487,7 @@ export def Expr(lnum = v:lnum): number # {{{2
|
||||
if line_A.text->ContinuesBelowBracketBlock(line_B, past_bracket_block)
|
||||
&& line_A.text !~ CLOSING_BRACKET_AT_SOL
|
||||
return past_bracket_block.startindent
|
||||
+ (past_bracket_block.startline =~ STARTS_NAMED_BLOCK ? 2 * shiftwidth() : 0)
|
||||
endif
|
||||
|
||||
# Problem: If we press `==` on the line right below the start of a multiline
|
||||
@ -438,6 +496,18 @@ export def Expr(lnum = v:lnum): number # {{{2
|
||||
if line_B->EndsWithLambdaArrow()
|
||||
return Indent(line_B.lnum) + shiftwidth() + IndentMoreInBracketBlock()
|
||||
endif
|
||||
# FIXME: Similar issue here:
|
||||
#
|
||||
# var x = []
|
||||
# ->filter((_, _) =>
|
||||
# true)
|
||||
# ->items()
|
||||
#
|
||||
# Press `==` on last line.
|
||||
# Expected: The `->items()` line is indented like `->filter(...)`.
|
||||
# Actual: It's indented like `true)`.
|
||||
# Is it worth fixing? `=ip` gives the correct indentation, because then the
|
||||
# cache is used.
|
||||
|
||||
# Don't move this block before the heredoc one.{{{
|
||||
#
|
||||
@ -536,8 +606,13 @@ def Offset( # {{{2
|
||||
line_B: dict<any>,
|
||||
): number
|
||||
|
||||
if line_B->AtStartOf('FuncHeader')
|
||||
&& IsInInterface()
|
||||
return 0
|
||||
|
||||
# increase indentation inside a block
|
||||
if line_B.text =~ STARTS_NAMED_BLOCK || line_B->EndsWithCurlyBlock()
|
||||
elseif line_B.text =~ STARTS_NAMED_BLOCK
|
||||
|| line_B->EndsWithCurlyBlock()
|
||||
# But don't indent if the line starting the block also closes it.
|
||||
if line_B->AlsoClosesBlock()
|
||||
return 0
|
||||
@ -807,11 +882,6 @@ def Indent(lnum: number): number # {{{3
|
||||
return indent(lnum)
|
||||
enddef
|
||||
|
||||
def BlockStartKeyword(line: string): string # {{{3
|
||||
var kwd: string = line->matchstr('\l\+')
|
||||
return fullcommand(kwd, false)
|
||||
enddef
|
||||
|
||||
def MatchingOpenBracket(line: dict<any>): number # {{{3
|
||||
var end: string = line.text->matchstr(CLOSING_BRACKET)
|
||||
var start: string = {']': '[', '}': '{', ')': '('}[end]
|
||||
@ -908,7 +978,8 @@ def SearchPair( # {{{3
|
||||
if end == '[' || end == ']'
|
||||
e = e->escape('[]')
|
||||
endif
|
||||
return searchpair(s, middle, e, flags, (): bool => InCommentOrString(), stopline, TIMEOUT)
|
||||
return searchpair('\C' .. s, (middle == '' ? '' : '\C' .. middle), '\C' .. e,
|
||||
flags, (): bool => InCommentOrString(), stopline, TIMEOUT)
|
||||
enddef
|
||||
|
||||
def SearchPairStart( # {{{3
|
||||
@ -1016,6 +1087,10 @@ def IsInThisBlock(line_A: dict<any>, lnum: number): bool # {{{3
|
||||
return line_A.lnum <= end
|
||||
enddef
|
||||
|
||||
def IsInInterface(): bool # {{{3
|
||||
return SearchPair('interface', '', 'endinterface', 'nW') > 0
|
||||
enddef
|
||||
|
||||
def IsFirstLineOfCommand(line_1: dict<any>, line_2: dict<any>): bool # {{{3
|
||||
if line_1.text->Is_IN_KeywordForLoop(line_2.text)
|
||||
return false
|
||||
@ -1096,6 +1171,10 @@ def EndsWithOpeningBracket(line: dict<any>): bool # {{{3
|
||||
return NonCommentedMatch(line, OPENING_BRACKET_AT_EOL)
|
||||
enddef
|
||||
|
||||
def EndsWithClosingBracket(line: dict<any>): bool # {{{3
|
||||
return NonCommentedMatch(line, CLOSING_BRACKET_AT_EOL)
|
||||
enddef
|
||||
|
||||
def NonCommentedMatch(line: dict<any>, pat: string): bool # {{{3
|
||||
# Could happen if there is no code above us, and we're not on the 1st line.
|
||||
# In that case, `PrevCodeLine()` returns `{lnum: 0, line: ''}`.
|
||||
@ -1103,16 +1182,6 @@ def NonCommentedMatch(line: dict<any>, pat: string): bool # {{{3
|
||||
return false
|
||||
endif
|
||||
|
||||
if line.text =~ PLUS_MINUS_COMMAND
|
||||
return false
|
||||
endif
|
||||
|
||||
# In `argdelete *`, `*` is not a multiplication operator.
|
||||
# TODO: Other commands can accept `*` as an argument. Handle them too.
|
||||
if line.text =~ '\<argd\%[elete]\s\+\*\s*$'
|
||||
return false
|
||||
endif
|
||||
|
||||
# Technically, that's wrong. A line might start with a range and end with a
|
||||
# line continuation symbol. But it's unlikely. And it's useful to assume the
|
||||
# opposite because it prevents us from conflating a mark with an operator or
|
||||
@ -1179,24 +1248,7 @@ def NonCommentedMatch(line: dict<any>, pat: string): bool # {{{3
|
||||
return false
|
||||
endif
|
||||
|
||||
# `:help cd-`
|
||||
if line.text =~ CD_COMMAND
|
||||
return false
|
||||
endif
|
||||
|
||||
# At the end of a mapping, any character might appear; e.g. a paren:
|
||||
#
|
||||
# nunmap <buffer> (
|
||||
#
|
||||
# Don't conflate this with a line continuation symbol.
|
||||
if line.text =~ MAPPING_COMMAND
|
||||
return false
|
||||
endif
|
||||
|
||||
# not a comparison operator
|
||||
# vv
|
||||
# normal! ==
|
||||
if line.text =~ NORMAL_COMMAND
|
||||
if line.text =~ TRICKY_COMMANDS
|
||||
return false
|
||||
endif
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
" Vim autoload file for the tohtml plugin.
|
||||
" Maintainer: Ben Fritz <fritzophrenic@gmail.com>
|
||||
" Last Change: 2019 Aug 16
|
||||
" Last Change: 2023 Jan 01
|
||||
"
|
||||
" Additional contributors:
|
||||
"
|
||||
@ -351,63 +351,65 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
|
||||
let s:old_magic = &magic
|
||||
set magic
|
||||
|
||||
if s:settings.use_xhtml
|
||||
if s:settings.encoding != ""
|
||||
let xml_line = "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>"
|
||||
else
|
||||
let xml_line = "<?xml version=\"1.0\"?>"
|
||||
endif
|
||||
let tag_close = ' />'
|
||||
endif
|
||||
|
||||
let style = [s:settings.use_xhtml ? "" : '-->']
|
||||
let body_line = ''
|
||||
|
||||
let html = []
|
||||
let s:html5 = 0
|
||||
if s:settings.use_xhtml
|
||||
call add(html, xml_line)
|
||||
endif
|
||||
if s:settings.use_xhtml
|
||||
call add(html, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">")
|
||||
call add(html, '<html xmlns="http://www.w3.org/1999/xhtml">')
|
||||
elseif s:settings.use_css && !s:settings.no_pre
|
||||
call add(html, "<!DOCTYPE html>")
|
||||
call add(html, '<html>')
|
||||
let s:html5 = 1
|
||||
else
|
||||
call add(html, '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"')
|
||||
call add(html, ' "http://www.w3.org/TR/html4/loose.dtd">')
|
||||
call add(html, '<html>')
|
||||
endif
|
||||
call add(html, '<head>')
|
||||
|
||||
" include encoding as close to the top as possible, but only if not already
|
||||
" contained in XML information
|
||||
if s:settings.encoding != "" && !s:settings.use_xhtml
|
||||
if s:html5
|
||||
call add(html, '<meta charset="' . s:settings.encoding . '"' . tag_close)
|
||||
else
|
||||
call add(html, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . tag_close)
|
||||
if !s:settings.no_doc
|
||||
if s:settings.use_xhtml
|
||||
if s:settings.encoding != ""
|
||||
let xml_line = "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>"
|
||||
else
|
||||
let xml_line = "<?xml version=\"1.0\"?>"
|
||||
endif
|
||||
let tag_close = ' />'
|
||||
endif
|
||||
|
||||
let style = [s:settings.use_xhtml ? "" : '-->']
|
||||
let body_line = ''
|
||||
|
||||
let s:html5 = 0
|
||||
if s:settings.use_xhtml
|
||||
call add(html, xml_line)
|
||||
endif
|
||||
if s:settings.use_xhtml
|
||||
call add(html, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">")
|
||||
call add(html, '<html xmlns="http://www.w3.org/1999/xhtml">')
|
||||
elseif s:settings.use_css && !s:settings.no_pre
|
||||
call add(html, "<!DOCTYPE html>")
|
||||
call add(html, '<html>')
|
||||
let s:html5 = 1
|
||||
else
|
||||
call add(html, '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"')
|
||||
call add(html, ' "http://www.w3.org/TR/html4/loose.dtd">')
|
||||
call add(html, '<html>')
|
||||
endif
|
||||
call add(html, '<head>')
|
||||
|
||||
" include encoding as close to the top as possible, but only if not already
|
||||
" contained in XML information
|
||||
if s:settings.encoding != "" && !s:settings.use_xhtml
|
||||
if s:html5
|
||||
call add(html, '<meta charset="' . s:settings.encoding . '"' . tag_close)
|
||||
else
|
||||
call add(html, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . tag_close)
|
||||
endif
|
||||
endif
|
||||
|
||||
call add(html, '<title>diff</title>')
|
||||
call add(html, '<meta name="Generator" content="Vim/'.v:version/100.'.'.v:version%100.'"'.tag_close)
|
||||
call add(html, '<meta name="plugin-version" content="'.g:loaded_2html_plugin.'"'.tag_close)
|
||||
call add(html, '<meta name="settings" content="'.
|
||||
\ join(filter(keys(s:settings),'s:settings[v:val]'),',').
|
||||
\ ',prevent_copy='.s:settings.prevent_copy.
|
||||
\ ',use_input_for_pc='.s:settings.use_input_for_pc.
|
||||
\ '"'.tag_close)
|
||||
call add(html, '<meta name="colorscheme" content="'.
|
||||
\ (exists('g:colors_name')
|
||||
\ ? g:colors_name
|
||||
\ : 'none'). '"'.tag_close)
|
||||
|
||||
call add(html, '</head>')
|
||||
let body_line_num = len(html)
|
||||
call add(html, '<body'.(s:settings.line_ids ? ' onload="JumpToLine();"' : '').'>')
|
||||
endif
|
||||
|
||||
call add(html, '<title>diff</title>')
|
||||
call add(html, '<meta name="Generator" content="Vim/'.v:version/100.'.'.v:version%100.'"'.tag_close)
|
||||
call add(html, '<meta name="plugin-version" content="'.g:loaded_2html_plugin.'"'.tag_close)
|
||||
call add(html, '<meta name="settings" content="'.
|
||||
\ join(filter(keys(s:settings),'s:settings[v:val]'),',').
|
||||
\ ',prevent_copy='.s:settings.prevent_copy.
|
||||
\ ',use_input_for_pc='.s:settings.use_input_for_pc.
|
||||
\ '"'.tag_close)
|
||||
call add(html, '<meta name="colorscheme" content="'.
|
||||
\ (exists('g:colors_name')
|
||||
\ ? g:colors_name
|
||||
\ : 'none'). '"'.tag_close)
|
||||
|
||||
call add(html, '</head>')
|
||||
let body_line_num = len(html)
|
||||
call add(html, '<body'.(s:settings.line_ids ? ' onload="JumpToLine();"' : '').'>')
|
||||
call add(html, "<table ".(s:settings.use_css? "" : "border='1' width='100%' ")."id='vimCodeElement".s:settings.id_suffix."'>")
|
||||
|
||||
call add(html, '<tr>')
|
||||
@ -430,47 +432,53 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
|
||||
" When not using CSS or when using xhtml, the <body> line can be important.
|
||||
" Assume it will be the same for all buffers and grab it from the first
|
||||
" buffer. Similarly, need to grab the body end line as well.
|
||||
if body_line == ''
|
||||
if !s:settings.no_doc
|
||||
if body_line == ''
|
||||
1
|
||||
call search('<body')
|
||||
let body_line = getline('.')
|
||||
$
|
||||
call search('</body>', 'b')
|
||||
let s:body_end_line = getline('.')
|
||||
endif
|
||||
|
||||
" Grab the style information. Some of this will be duplicated so only insert
|
||||
" it if it's not already there. {{{
|
||||
1
|
||||
call search('<body')
|
||||
let body_line = getline('.')
|
||||
$
|
||||
call search('</body>', 'b')
|
||||
let s:body_end_line = getline('.')
|
||||
endif
|
||||
|
||||
" Grab the style information. Some of this will be duplicated so only insert
|
||||
" it if it's not already there. {{{
|
||||
1
|
||||
let style_start = search('^<style\( type="text/css"\)\?>')
|
||||
1
|
||||
let style_end = search('^</style>')
|
||||
if style_start > 0 && style_end > 0
|
||||
let buf_styles = getline(style_start + 1, style_end - 1)
|
||||
for a_style in buf_styles
|
||||
if index(style, a_style) == -1
|
||||
if diff_style_start == 0
|
||||
if a_style =~ '\<Diff\(Change\|Text\|Add\|Delete\)'
|
||||
let diff_style_start = len(style)-1
|
||||
let style_start = search('^<style\( type="text/css"\)\?>')
|
||||
1
|
||||
let style_end = search('^</style>')
|
||||
if style_start > 0 && style_end > 0
|
||||
let buf_styles = getline(style_start + 1, style_end - 1)
|
||||
for a_style in buf_styles
|
||||
if index(style, a_style) == -1
|
||||
if diff_style_start == 0
|
||||
if a_style =~ '\<Diff\(Change\|Text\|Add\|Delete\)'
|
||||
let diff_style_start = len(style)-1
|
||||
endif
|
||||
endif
|
||||
call insert(style, a_style, insert_index)
|
||||
let insert_index += 1
|
||||
endif
|
||||
call insert(style, a_style, insert_index)
|
||||
let insert_index += 1
|
||||
endif
|
||||
endfor
|
||||
endif " }}}
|
||||
endfor
|
||||
endif " }}}
|
||||
|
||||
" everything new will get added before the diff styles so diff highlight
|
||||
" properly overrides normal highlight
|
||||
if diff_style_start != 0
|
||||
let insert_index = diff_style_start
|
||||
" everything new will get added before the diff styles so diff highlight
|
||||
" properly overrides normal highlight
|
||||
if diff_style_start != 0
|
||||
let insert_index = diff_style_start
|
||||
endif
|
||||
|
||||
" Delete those parts that are not needed so we can include the rest into the
|
||||
" resulting table.
|
||||
1,/^<body.*\%(\n<!--.*-->\_s\+.*id='oneCharWidth'.*\_s\+.*id='oneInputWidth'.*\_s\+.*id='oneEmWidth'\)\?\zs/d_
|
||||
$
|
||||
?</body>?,$d_
|
||||
elseif !s:settings.no_modeline
|
||||
" remove modeline from source files if it is included and we haven't deleted
|
||||
" due to removing html footer already
|
||||
$d
|
||||
endif
|
||||
|
||||
" Delete those parts that are not needed so we can include the rest into the
|
||||
" resulting table.
|
||||
1,/^<body.*\%(\n<!--.*-->\_s\+.*id='oneCharWidth'.*\_s\+.*id='oneInputWidth'.*\_s\+.*id='oneEmWidth'\)\?\zs/d_
|
||||
$
|
||||
?</body>?,$d_
|
||||
let temp = getline(1,'$')
|
||||
" clean out id on the main content container because we already set it on
|
||||
" the table
|
||||
@ -478,7 +486,11 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
|
||||
" undo deletion of start and end part
|
||||
" so we can later save the file as valid html
|
||||
" TODO: restore using grabbed lines if undolevel is 1?
|
||||
normal! 2u
|
||||
if !s:settings.no_doc
|
||||
normal! 2u
|
||||
elseif !s:settings.no_modeline
|
||||
normal! u
|
||||
endif
|
||||
if s:settings.use_css
|
||||
call add(html, '<td><div>')
|
||||
elseif s:settings.use_xhtml
|
||||
@ -495,17 +507,23 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
|
||||
quit!
|
||||
endfor
|
||||
|
||||
let html[body_line_num] = body_line
|
||||
if !s:settings.no_doc
|
||||
let html[body_line_num] = body_line
|
||||
endif
|
||||
|
||||
call add(html, '</tr>')
|
||||
call add(html, '</table>')
|
||||
call add(html, s:body_end_line)
|
||||
call add(html, '</html>')
|
||||
if !s:settings.no_doc
|
||||
call add(html, s:body_end_line)
|
||||
call add(html, '</html>')
|
||||
endif
|
||||
|
||||
" The generated HTML is admittedly ugly and takes a LONG time to fold.
|
||||
" Make sure the user doesn't do syntax folding when loading a generated file,
|
||||
" using a modeline.
|
||||
call add(html, '<!-- vim: set foldmethod=manual : -->')
|
||||
if !s:settings.no_modeline
|
||||
call add(html, '<!-- vim: set foldmethod=manual : -->')
|
||||
endif
|
||||
|
||||
let i = 1
|
||||
let name = "Diff" . (s:settings.use_xhtml ? ".xhtml" : ".html")
|
||||
@ -542,129 +560,131 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
|
||||
|
||||
call append(0, html)
|
||||
|
||||
if len(style) > 0
|
||||
1
|
||||
let style_start = search('^</head>')-1
|
||||
if !s:settings.no_doc
|
||||
if len(style) > 0
|
||||
1
|
||||
let style_start = search('^</head>')-1
|
||||
|
||||
" add required javascript in reverse order so we can just call append again
|
||||
" and again without adjusting {{{
|
||||
" add required javascript in reverse order so we can just call append again
|
||||
" and again without adjusting {{{
|
||||
|
||||
let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids
|
||||
let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids
|
||||
|
||||
" insert script closing tag if needed
|
||||
if s:uses_script
|
||||
call append(style_start, [
|
||||
\ '',
|
||||
\ s:settings.use_xhtml ? '//]]>' : '-->',
|
||||
\ "</script>"
|
||||
\ ])
|
||||
endif
|
||||
|
||||
" insert javascript to get IDs from line numbers, and to open a fold before
|
||||
" jumping to any lines contained therein
|
||||
if s:settings.line_ids
|
||||
call append(style_start, [
|
||||
\ " /* Always jump to new location even if the line was hidden inside a fold, or",
|
||||
\ " * we corrected the raw number to a line ID.",
|
||||
\ " */",
|
||||
\ " if (lineElem) {",
|
||||
\ " lineElem.scrollIntoView(true);",
|
||||
\ " }",
|
||||
\ " return true;",
|
||||
\ "}",
|
||||
\ "if ('onhashchange' in window) {",
|
||||
\ " window.onhashchange = JumpToLine;",
|
||||
\ "}"
|
||||
\ ])
|
||||
|
||||
if s:settings.dynamic_folds
|
||||
" insert script closing tag if needed
|
||||
if s:uses_script
|
||||
call append(style_start, [
|
||||
\ "",
|
||||
\ " /* navigate upwards in the DOM tree to open all folds containing the line */",
|
||||
\ " var node = lineElem;",
|
||||
\ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
|
||||
\ " {",
|
||||
\ " if (node.className == 'closed-fold')",
|
||||
\ " {",
|
||||
\ " /* toggle open the fold ID (remove window ID) */",
|
||||
\ " toggleFold(node.id.substr(4));",
|
||||
\ " }",
|
||||
\ " node = node.parentNode;",
|
||||
\ " }",
|
||||
\ '',
|
||||
\ s:settings.use_xhtml ? '//]]>' : '-->',
|
||||
\ "</script>"
|
||||
\ ])
|
||||
endif
|
||||
endif
|
||||
|
||||
if s:settings.line_ids
|
||||
call append(style_start, [
|
||||
\ "",
|
||||
\ "/* function to open any folds containing a jumped-to line before jumping to it */",
|
||||
\ "function JumpToLine()",
|
||||
\ "{",
|
||||
\ " var lineNum;",
|
||||
\ " lineNum = window.location.hash;",
|
||||
\ " lineNum = lineNum.substr(1); /* strip off '#' */",
|
||||
\ "",
|
||||
\ " if (lineNum.indexOf('L') == -1) {",
|
||||
\ " lineNum = 'L'+lineNum;",
|
||||
\ " }",
|
||||
\ " if (lineNum.indexOf('W') == -1) {",
|
||||
\ " lineNum = 'W1'+lineNum;",
|
||||
\ " }",
|
||||
\ " var lineElem = document.getElementById(lineNum);"
|
||||
\ ])
|
||||
endif
|
||||
" insert javascript to get IDs from line numbers, and to open a fold before
|
||||
" jumping to any lines contained therein
|
||||
if s:settings.line_ids
|
||||
call append(style_start, [
|
||||
\ " /* Always jump to new location even if the line was hidden inside a fold, or",
|
||||
\ " * we corrected the raw number to a line ID.",
|
||||
\ " */",
|
||||
\ " if (lineElem) {",
|
||||
\ " lineElem.scrollIntoView(true);",
|
||||
\ " }",
|
||||
\ " return true;",
|
||||
\ "}",
|
||||
\ "if ('onhashchange' in window) {",
|
||||
\ " window.onhashchange = JumpToLine;",
|
||||
\ "}"
|
||||
\ ])
|
||||
|
||||
" Insert javascript to toggle matching folds open and closed in all windows,
|
||||
" if dynamic folding is active.
|
||||
if s:settings.dynamic_folds
|
||||
call append(style_start, [
|
||||
\ " function toggleFold(objID)",
|
||||
\ " {",
|
||||
\ " for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)",
|
||||
\ " {",
|
||||
\ " var fold;",
|
||||
\ ' fold = document.getElementById("win"+win_num+objID);',
|
||||
\ " if(fold.className == 'closed-fold')",
|
||||
\ " {",
|
||||
\ " fold.className = 'open-fold';",
|
||||
\ " }",
|
||||
\ " else if (fold.className == 'open-fold')",
|
||||
\ " {",
|
||||
\ " fold.className = 'closed-fold';",
|
||||
\ " }",
|
||||
\ " }",
|
||||
\ " }",
|
||||
\ ])
|
||||
endif
|
||||
if s:settings.dynamic_folds
|
||||
call append(style_start, [
|
||||
\ "",
|
||||
\ " /* navigate upwards in the DOM tree to open all folds containing the line */",
|
||||
\ " var node = lineElem;",
|
||||
\ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
|
||||
\ " {",
|
||||
\ " if (node.className == 'closed-fold')",
|
||||
\ " {",
|
||||
\ " /* toggle open the fold ID (remove window ID) */",
|
||||
\ " toggleFold(node.id.substr(4));",
|
||||
\ " }",
|
||||
\ " node = node.parentNode;",
|
||||
\ " }",
|
||||
\ ])
|
||||
endif
|
||||
endif
|
||||
|
||||
if s:uses_script
|
||||
" insert script tag if needed
|
||||
call append(style_start, [
|
||||
\ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">",
|
||||
\ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
|
||||
endif
|
||||
if s:settings.line_ids
|
||||
call append(style_start, [
|
||||
\ "",
|
||||
\ "/* function to open any folds containing a jumped-to line before jumping to it */",
|
||||
\ "function JumpToLine()",
|
||||
\ "{",
|
||||
\ " var lineNum;",
|
||||
\ " lineNum = window.location.hash;",
|
||||
\ " lineNum = lineNum.substr(1); /* strip off '#' */",
|
||||
\ "",
|
||||
\ " if (lineNum.indexOf('L') == -1) {",
|
||||
\ " lineNum = 'L'+lineNum;",
|
||||
\ " }",
|
||||
\ " if (lineNum.indexOf('W') == -1) {",
|
||||
\ " lineNum = 'W1'+lineNum;",
|
||||
\ " }",
|
||||
\ " var lineElem = document.getElementById(lineNum);"
|
||||
\ ])
|
||||
endif
|
||||
|
||||
" Insert styles from all the generated html documents and additional styles
|
||||
" for the table-based layout of the side-by-side diff. The diff should take
|
||||
" up the full browser window (but not more), and be static in size,
|
||||
" horizontally scrollable when the lines are too long. Otherwise, the diff
|
||||
" is pretty useless for really long lines. {{{
|
||||
if s:settings.use_css
|
||||
call append(style_start,
|
||||
\ ['<style' . (s:html5 ? '' : 'type="text/css"') . '>']+
|
||||
\ style+
|
||||
\ [ s:settings.use_xhtml ? '' : '<!--',
|
||||
\ 'table { table-layout: fixed; }',
|
||||
\ 'html, body, table, tbody { width: 100%; margin: 0; padding: 0; }',
|
||||
\ 'table, td, th { border: 1px solid; }',
|
||||
\ 'td { vertical-align: top; }',
|
||||
\ 'th, td { width: '.printf("%.1f",100.0/len(a:win_list)).'%; }',
|
||||
\ 'td div { overflow: auto; }',
|
||||
\ s:settings.use_xhtml ? '' : '-->',
|
||||
\ '</style>'
|
||||
\])
|
||||
endif "}}}
|
||||
" Insert javascript to toggle matching folds open and closed in all windows,
|
||||
" if dynamic folding is active.
|
||||
if s:settings.dynamic_folds
|
||||
call append(style_start, [
|
||||
\ " function toggleFold(objID)",
|
||||
\ " {",
|
||||
\ " for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)",
|
||||
\ " {",
|
||||
\ " var fold;",
|
||||
\ ' fold = document.getElementById("win"+win_num+objID);',
|
||||
\ " if(fold.className == 'closed-fold')",
|
||||
\ " {",
|
||||
\ " fold.className = 'open-fold';",
|
||||
\ " }",
|
||||
\ " else if (fold.className == 'open-fold')",
|
||||
\ " {",
|
||||
\ " fold.className = 'closed-fold';",
|
||||
\ " }",
|
||||
\ " }",
|
||||
\ " }",
|
||||
\ ])
|
||||
endif
|
||||
|
||||
if s:uses_script
|
||||
" insert script tag if needed
|
||||
call append(style_start, [
|
||||
\ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">",
|
||||
\ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
|
||||
endif
|
||||
|
||||
" Insert styles from all the generated html documents and additional styles
|
||||
" for the table-based layout of the side-by-side diff. The diff should take
|
||||
" up the full browser window (but not more), and be static in size,
|
||||
" horizontally scrollable when the lines are too long. Otherwise, the diff
|
||||
" is pretty useless for really long lines. {{{
|
||||
if s:settings.use_css
|
||||
call append(style_start,
|
||||
\ ['<style' . (s:html5 ? '' : 'type="text/css"') . '>']+
|
||||
\ style+
|
||||
\ [ s:settings.use_xhtml ? '' : '<!--',
|
||||
\ 'table { table-layout: fixed; }',
|
||||
\ 'html, body, table, tbody { width: 100%; margin: 0; padding: 0; }',
|
||||
\ 'table, td, th { border: 1px solid; }',
|
||||
\ 'td { vertical-align: top; }',
|
||||
\ 'th, td { width: '.printf("%.1f",100.0/len(a:win_list)).'%; }',
|
||||
\ 'td div { overflow: auto; }',
|
||||
\ s:settings.use_xhtml ? '' : '-->',
|
||||
\ '</style>'
|
||||
\])
|
||||
endif "}}}
|
||||
endif
|
||||
endif
|
||||
|
||||
let &paste = s:old_paste
|
||||
|
||||
Reference in New Issue
Block a user