mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 01:40:05 +08:00
250 lines
5.7 KiB
VimL
250 lines
5.7 KiB
VimL
" vim: foldmethod=marker
|
|
|
|
" Split / Join {{{1
|
|
"
|
|
" function! sj#elm#JoinBraces() {{{2
|
|
"
|
|
" Attempts to join the multiline tuple, record or list closest
|
|
" to current cursor position.
|
|
function! sj#elm#JoinBraces()
|
|
let [from, to] = s:ClosestMultilineBraces()
|
|
|
|
if from[0] < 0
|
|
return 0
|
|
endif
|
|
|
|
let original = sj#GetByPosition([0, from[0], from[1]], [0, to[0], to[1]])
|
|
let joined = s:JoinOuterBraces(s:JoinLines(original))
|
|
call sj#ReplaceByPosition([0, from[0], from[1]], [0, to[0], to[1]], joined)
|
|
|
|
return 1
|
|
endfunction
|
|
|
|
" function! sj#elm#SplitBraces() {{{2
|
|
"
|
|
" Attempts to split the tuple, record or list furthest to current
|
|
" cursor position on the same line.
|
|
function! sj#elm#SplitBraces()
|
|
try
|
|
call sj#PushCursor()
|
|
|
|
let [from, to] = s:CurrentLineOutermostBraces(col('.'))
|
|
|
|
if from < 0
|
|
return 0
|
|
endif
|
|
|
|
let parts = s:SplitParts(from, to)
|
|
|
|
if len(parts) <= 2
|
|
return 0
|
|
endif
|
|
|
|
let replacement = join(parts, "\n")
|
|
|
|
call cursor(line('.'), from)
|
|
let [previousLine, previousCol] = searchpos('\S', 'bn')
|
|
if previousLine == line('.') && previousCol > 0 && s:CharAt(previousCol) =~ '[=:]'
|
|
let replacement = "\n".replacement
|
|
let from = previousCol + 1
|
|
end
|
|
|
|
call sj#ReplaceCols(from, to, replacement)
|
|
|
|
return 1
|
|
finally
|
|
call sj#PopCursor()
|
|
endtry
|
|
endfunction
|
|
|
|
|
|
" Helper functions {{{1
|
|
|
|
" function! s:SkipSyntax() {{{2
|
|
"
|
|
" Returns Elm's typical skippable syntax (strings and comments)
|
|
function! s:SkipSyntax()
|
|
return sj#SkipSyntax(['elmString', 'elmTripleString', 'elmComment'])
|
|
endfunction
|
|
|
|
" function! s:CurrentLineClosestBraces(column) {{{2
|
|
"
|
|
" Returns the columns corresponding to the bracing pair closest
|
|
" to and surrounding given column as a list ([opening, closing]).
|
|
" Returns [-1, -1] when there is none on the same line.
|
|
function! s:CurrentLineClosestBraces(column)
|
|
try
|
|
call sj#PushCursor()
|
|
|
|
let skip = s:SkipSyntax()
|
|
let currentLine = line('.')
|
|
|
|
call cursor(currentLine, a:column)
|
|
let from = searchpairpos('[{(\[]', '', '[})\]]', 'bcn', skip, currentLine)
|
|
|
|
if from[0] == 0
|
|
return [-1, -1]
|
|
end
|
|
|
|
call cursor(from[0], from[1])
|
|
normal! %
|
|
|
|
if line('.') != currentLine
|
|
return [-1, -1]
|
|
endif
|
|
|
|
let to = col('.')
|
|
|
|
return [from[1], to]
|
|
finally
|
|
call sj#PopCursor()
|
|
endtry
|
|
endfunction
|
|
|
|
" function! s:CurrentLineOutermostBraces(column) {{{2
|
|
"
|
|
" Returns the colums corresponding to the bracing pair furthest
|
|
" to and surrounding given column as a list ([opening, closing]).
|
|
" Returns [-1, -1] when there is none on the same line.
|
|
function! s:CurrentLineOutermostBraces(column)
|
|
if a:column < 1
|
|
return [-1, -1]
|
|
endif
|
|
|
|
let currentMatch = s:CurrentLineClosestBraces(a:column)
|
|
|
|
if currentMatch[0] < 1
|
|
return [-1, -1]
|
|
endif
|
|
|
|
let betterMatch = s:CurrentLineOutermostBraces(currentMatch[0] - 1)
|
|
|
|
if betterMatch[0] < 1
|
|
return currentMatch
|
|
endif
|
|
|
|
return betterMatch
|
|
endfunction
|
|
|
|
" function! s:ClosestMultilineBraces() {{{2
|
|
"
|
|
" Returns the position of the closest pair of multiline braces
|
|
" around the cursor.
|
|
"
|
|
" The positions are given as a couple of arrays:
|
|
"
|
|
" [[startLine, startCol], [endLine, endCol]]
|
|
"
|
|
" When no position is found, returns:
|
|
"
|
|
" [[-1, -1], [-1, -1]]
|
|
function! s:ClosestMultilineBraces()
|
|
try
|
|
call sj#PushCursor()
|
|
|
|
let skip = s:SkipSyntax()
|
|
|
|
let currentLine = line('.')
|
|
|
|
normal! $
|
|
|
|
let [toLine, toCol] = searchpairpos('[{(\[]', '', '[})\]]', '', skip, line('$'))
|
|
|
|
if toLine < currentLine
|
|
return [[-1, -1], [-1, -1]]
|
|
endif
|
|
|
|
normal! %
|
|
|
|
let fromLine = line('.')
|
|
let fromCol = col('.')
|
|
|
|
if fromLine >= toLine
|
|
return [[-1, -1], [-1, -1]]
|
|
endif
|
|
|
|
return [[fromLine, fromCol], [toLine, toCol]]
|
|
finally
|
|
call sj#PopCursor()
|
|
endtry
|
|
endfunction
|
|
|
|
" function! s:JoinOuterBraces(text)
|
|
"
|
|
" Removes spaces separating the first and last char of a string
|
|
" with the closest non-space char found.
|
|
"
|
|
" ex:
|
|
"
|
|
" [ 1, 2, 3 ] => [1, 2, 3]
|
|
function! s:JoinOuterBraces(text)
|
|
return substitute(substitute(a:text, '\s*\(.\)$', '\1', ''), '^\(.\)\s*', '\1', '')
|
|
endfunction
|
|
|
|
" function! s:JoinLines(text)
|
|
"
|
|
" Joins lines in text, removing complementary spaces around
|
|
" newline chars when the last line starts with a ',' and keeping
|
|
" one whitespace for other cases.
|
|
function! s:JoinLines(text)
|
|
return substitute(substitute(a:text, '\s*\n\s*,', ',', 'g'), '\s*\n\s*', ' ', 'g')
|
|
endfunction
|
|
|
|
" function! s:SplitParts(from, to)
|
|
"
|
|
" Splits a section of a line according to bracing characters
|
|
" rules.
|
|
"
|
|
" ex:
|
|
" "[1,2,3]"
|
|
" v
|
|
" [ "[ 1", ", 2", ", 3", "]" ]
|
|
"
|
|
" "{a | foo = bar, baz = buzz}"
|
|
" v
|
|
" [ "{ a", "| foo = bar", ", baz = buzz", "}" ]
|
|
function! s:SplitParts(from, to)
|
|
try
|
|
call sj#PushCursor()
|
|
let skip = s:SkipSyntax()
|
|
let currentLine = line('.')
|
|
|
|
call cursor(currentLine, a:from)
|
|
|
|
let openingCol = a:from
|
|
let openingChar = s:CurrentChar()
|
|
let parts = []
|
|
|
|
while col('.') < a:to
|
|
call searchpair('[{(\[]', ',\|\(\(<\)\@<!|\(>\)\@!\)', '[})\]]', '', skip, currentLine)
|
|
let closingCol = col('.')
|
|
let closingChar = s:CurrentChar()
|
|
let part = openingChar.' '.sj#Trim(sj#GetByPosition([0, currentLine, openingCol + 1, 0], [0, currentLine, closingCol - 1, 0]))
|
|
call add(parts, part)
|
|
let openingCol = closingCol
|
|
let openingChar = closingChar
|
|
call cursor(currentLine, openingCol)
|
|
endwhile
|
|
|
|
call add(parts, s:CharAt(a:to))
|
|
|
|
return parts
|
|
finally
|
|
call sj#PopCursor()
|
|
endtry
|
|
endfunction
|
|
|
|
" function! s:CharAt(column)
|
|
"
|
|
" Returns the char sitting at given column of current line.
|
|
function! s:CharAt(column)
|
|
return getline('.')[a:column - 1]
|
|
endfunction
|
|
|
|
" function! s:CurrentChar()
|
|
"
|
|
" Returns the character at current cursor's position
|
|
function! s:CurrentChar()
|
|
return s:CharAt(col('.'))
|
|
endfunction
|