1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 13:00:05 +08:00
SpaceVim/bundle/vim-javacomplete2/autoload/javacomplete/generators.vim
2022-11-02 00:34:34 +08:00

635 lines
20 KiB
VimL
Vendored

" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Source code generators
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[generators] ". log)
endfunction
let g:JavaComplete_Templates = {}
let g:JavaComplete_Generators = {}
let g:JavaComplete_Templates['setter'] =
\ "$modifiers void $funcname($type $varname) {\n" .
\ "$accessor.$varname = $varname;\n" .
\ "}"
let g:JavaComplete_Templates['getter'] =
\ "$modifiers $type $funcname() {\n" .
\ "return $varname;\n" .
\ "}"
let g:JavaComplete_Templates['abstractDeclaration'] =
\ "@Override\n" .
\ "$declaration {\n" .
\ "throw new UnsupportedOperationException();\n" .
\ "}"
function! s:CollectVars()
let currentFileVars = []
for d in s:ti.defs
if d.tag == 'VARDEF'
let var = s:GetVariable(s:ti.name, d)
call add(currentFileVars, var)
endif
endfor
return currentFileVars
endfunction
function! javacomplete#generators#GenerateClass(options, ...)
let template = a:0 > 0 && !empty(a:1) ? '_'. a:1 : ''
let classCommand = {'template': 'class'. template, 'options': a:options, 'position_type' : 1}
call <SID>generateByTemplate(classCommand)
endfunction
function! javacomplete#generators#GenerateConstructor(default)
let defaultConstructorCommand = {'key': '1', 'desc': 'generate default constructor', 'call': '<SID>generateByTemplate', 'template': 'constructor', 'replace': {'type': 'same'}, 'options': {'default': 1}}
if a:default == 0
let commands = [
\ defaultConstructorCommand,
\ {'key': '2', 'desc': 'generate constructor', 'call': '<SID>generateByTemplate', 'template': 'constructor', 'replace': {'type': 'same'}}
\ ]
call s:FieldsListBuffer(commands)
else
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let s:savedCursorPosition = getpos('.')
call <SID>generateByTemplate(defaultConstructorCommand)
endif
endfunction
function! javacomplete#generators#GenerateEqualsAndHashCode()
let commands = [
\ {'key': '1', 'desc': 'generate `equals` method', 'call': '<SID>generateByTemplate', 'template': 'equals', 'replace': {'type': 'similar'}},
\ {'key': '2', 'desc': 'generate `hashCode` method', 'call': '<SID>generateByTemplate', 'template': 'hashCode', 'replace': {'type': 'similar'}},
\ {'key': '3', 'desc': 'generate `equals` and `hashCode` methods', 'call': '<SID>generateByTemplate', 'template': ['hashCode', 'equals'], 'replace': {'type': 'similar'}}
\ ]
call s:FieldsListBuffer(commands)
endfunction
function! javacomplete#generators#GenerateToString()
let commands = [
\ {'key': '1', 'desc': 'generate `toString` method using concatination', 'call': '<SID>generateByTemplate', 'template': 'toString_concat', 'replace': {'type': 'similar'}},
\ {'key': '2', 'desc': 'generate `toString` method using StringBuilder', 'call': '<SID>generateByTemplate', 'template': 'toString_StringBuilder', 'replace': {'type': 'similar'}}
\ ]
call s:FieldsListBuffer(commands)
endfunction
function! s:FieldsListBuffer(commands)
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let s:savedCursorPosition = getpos('.')
let contentLine = s:CreateBuffer("__FieldsListBuffer__", "remove unnecessary fields", a:commands)
let b:currentFileVars = s:CollectVars()
let lines = ""
let idx = 0
while idx < len(b:currentFileVars)
let var = b:currentFileVars[idx]
let lines = lines. "\n". "f". idx. " --> ". var.type . " ". var.name
let idx += 1
endwhile
silent put = lines
call cursor(contentLine + 1, 0)
endfunction
function! javacomplete#generators#GenerateByTemplate(command)
call <SID>generateByTemplate(a:command)
endfunction
" a:1 - method declaration to replace
function! <SID>generateByTemplate(command)
let command = a:command
if !has_key(command, 'fields')
let command['fields'] = []
endif
if bufname('%') == "__FieldsListBuffer__"
call s:Log("generate method with template: ". string(command.template))
let currentBuf = getline(1,'$')
for line in currentBuf
if line =~ '^f[0-9]\+.*'
let cmd = line[0]
let idx = line[1:stridx(line, ' ')-1]
let var = b:currentFileVars[idx]
call add(command['fields'], var)
endif
endfor
execute "bwipeout!"
endif
let result = []
let templates = type(command.template) != type([]) ? [command.template] : command.template
let class = {}
if has_key(s:, 'ti')
let class['name'] = s:ti.name
endif
let class['fields'] = command['fields']
for template in templates
call s:CheckAndLoadTemplate(template)
if has_key(g:JavaComplete_Generators, template)
call s:Log(g:JavaComplete_Generators[template]['data'])
execute g:JavaComplete_Generators[template]['data']
let arguments = [class]
if has_key(command, 'options')
call add(arguments, command.options)
endif
let TemplateFunction = function('s:__'. template)
for line in split(call(TemplateFunction, arguments), '\n')
call add(result, line)
endfor
call add(result, '')
endif
endfor
if len(result) > 0
if has_key(command, 'replace')
let toReplace = []
if command.replace.type == 'same'
let defs = s:GetNewMethodsDefinitions(result)
for def in defs
call add(toReplace, def.d)
endfor
elseif command.replace.type == 'similar'
let defs = s:GetNewMethodsDefinitions(result)
for def in defs
let m = s:FindMethod(s:ti.methods, def)
if !empty(m)
call add(toReplace, m.d)
endif
endfor
endif
let idx = 0
while idx < len(s:ti.defs)
let def = s:ti.defs[idx]
if get(def, 'tag', '') == 'METHODDEF'
\ && index(toReplace, get(def, 'd', '')) > -1
\ && has_key(def, 'body') && has_key(def.body, 'endpos')
let startline = java_parser#DecodePos(def.pos).line
if !empty(getline(startline))
let startline += 1
endif
let endline = java_parser#DecodePos(def.body.endpos).line + 1
silent! execute startline.','.endline. 'delete _'
call setpos('.', s:savedCursorPosition)
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let idx = 0
else
let idx += 1
endif
endwhile
endif
if has_key(command, 'position_type')
call s:InsertResults(result, command['position_type'])
else
call s:InsertResults(result)
endif
if has_key(s:, 'savedCursorPosition')
call setpos('.', s:savedCursorPosition)
endif
endif
endfunction
function! s:CheckAndLoadTemplate(template)
let filenames = []
if isdirectory(g:JavaComplete_CustomTemplateDirectory)
call add(filenames, expand(g:JavaComplete_CustomTemplateDirectory). '/gen__'. a:template. '.tpl')
endif
call add(filenames, g:JavaComplete_Home. '/plugin/res/gen__'. a:template. '.tpl')
for filename in filenames
if filereadable(filename)
if has_key(g:JavaComplete_Generators, a:template)
if getftime(filename) > g:JavaComplete_Generators[a:template]['file_time']
let g:JavaComplete_Generators[a:template]['data'] = join(readfile(filename), "\n")
let g:JavaComplete_Generators[a:template]['file_time'] = getftime(filename)
endif
else
let g:JavaComplete_Generators[a:template] = {}
let g:JavaComplete_Generators[a:template]['data'] = join(readfile(filename), "\n")
let g:JavaComplete_Generators[a:template]['file_time'] = getftime(filename)
endif
break
endif
endfor
endfunction
function! javacomplete#generators#AbstractDeclaration()
let s:ti = javacomplete#collector#DoGetClassInfo('this')
if get(s:ti, 'interface', 0) == 1
return
endif
let s = ''
let abstractMethods = []
let implementedMethods = []
for i in get(s:ti, 'extends', [])
let parentInfo = javacomplete#collector#DoGetClassInfo(i)
let members = javacomplete#complete#complete#SearchMember(parentInfo, '', 1, 1, 1, 14, 0)
for m in members[1]
if javacomplete#util#CheckModifier(m.m, [g:JC_MODIFIER_ABSTRACT])
call add(abstractMethods, m)
elseif javacomplete#util#CheckModifier(m.m, [g:JC_MODIFIER_PUBLIC])
call add(implementedMethods, m)
endif
endfor
unlet i
endfor
let result = []
let method = g:JavaComplete_Templates['abstractDeclaration']
for m in abstractMethods
if !empty(s:CheckImplementationExistense(s:ti, implementedMethods, m))
continue
endif
let declaration = javacomplete#util#GenMethodParamsDeclaration(m)
let declaration = substitute(declaration, '\<\(abstract\|default\|native\)\s\+', '', 'g')
let declaration = javacomplete#util#CleanFQN(declaration)
call add(result, '')
for line in split(substitute(method, '$declaration', declaration, 'g'), '\n')
call add(result, line)
endfor
call add(implementedMethods, m)
endfor
call s:InsertResults(result)
endfunction
" ti - this class info
" implementedMethods - implemented methods from parent class
" method - method to check
function! s:CheckImplementationExistense(ti, implementedMethods, method)
let methods = a:ti.methods
call extend(methods, a:implementedMethods)
return s:FindMethod(methods, a:method)
endfunction
function! s:GetParams(params)
let params = []
for param in a:params
if type(param) == type({}) && has_key(param, 'type')
if has_key(param.type, 'name')
call add(params, javacomplete#util#CleanFQN(param.type.name))
elseif has_key(param.type, 'clazz') && has_key(param.type.clazz, 'name')
let name = javacomplete#util#CleanFQN(param.type.clazz.name)
if has_key(param.type, 'arguments')
let args = []
for arg in param.type.arguments
if type(arg) == type({})
if len(arg.name) == 1
call add(params, '\('. g:RE_TYPE_ARGUMENT_EXTENDS. '\|'. g:RE_TYPE. '\)')
else
call add(params, arg.name)
endif
else
call add(params, '?')
endif
endfor
let name .= '<'. join(args, ',\s*'). '>'
endif
call add(params, name)
elseif has_key(param.type, 'typetag')
call add(params, param.type.typetag)
elseif has_key(param.type, 'tag') && param.type.tag == 'TYPEARRAY'
if has_key(param.type, 'elementtype') && has_key(param.type.elementtype, 'name')
call add(params, param.type.elementtype.name . '[]')
endif
endif
endif
endfor
return params
endfunction
function! s:FindMethod(methods, method)
let searchMethodParamList = []
if has_key(a:method, 'p')
for p in a:method.p
call add(searchMethodParamList, javacomplete#util#CleanFQN(p))
endfor
elseif has_key(a:method, 'params')
call extend(searchMethodParamList, s:GetParams(a:method.params))
endif
let methodDeclaration = javacomplete#util#CleanFQN(a:method.r . ' '. a:method.n)
for method in a:methods
if methodDeclaration ==# javacomplete#util#CleanFQN(method.r . ' '. method.n)
let methodParamList = []
if has_key(method, 'params')
call extend(methodParamList, s:GetParams(method.params))
elseif has_key(method, 'p')
for param in method.p
if type(param) == type("")
call add(methodParamList, javacomplete#util#CleanFQN(param))
endif
endfor
endif
" compare parameters need to be done with regexp because of separator of
" arguments if paramater has generic arguments
let i = 0
let _continue = 0
for p in searchMethodParamList
if i < len(methodParamList)
if p !~ methodParamList[i]
let _continue = 1
break
endif
else
let _continue = 1
break
endif
let i += 1
endfor
if _continue == 1
continue
endif
return method
endif
endfor
return {}
endfunction
function! s:CreateBuffer(name, title, commands)
let n = bufwinnr(a:name)
if n != -1
execute "bwipeout!"
endif
exec 'silent! split '. a:name
" Mark the buffer as scratch
setlocal buftype=nofile
setlocal bufhidden=wipe
setlocal noswapfile
setlocal nowrap
setlocal nobuflisted
nnoremap <buffer> <silent> q :bwipeout!<CR>
syn match Comment "^\".*"
put = '\"-----------------------------------------------------'
put = '\" '. a:title
put = '\" '
put = '\" q - close this window'
for command in a:commands
put = '\" '. command.key . ' - '. command.desc
if has_key(command, 'call')
exec "nnoremap <buffer> <silent> ". command.key . " :call ". command.call . "(". string(command). ")<CR>"
endif
endfor
put = '\"-----------------------------------------------------'
return line(".") + 1
endfunction
function! javacomplete#generators#Accessors()
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let commands = [{'key': 's', 'desc': 'generate accessors', 'call': '<SID>generateAccessors'}]
let contentLine = s:CreateBuffer("__AccessorsBuffer__", "remove unnecessary accessors", commands)
let b:currentFileVars = s:CollectVars()
let lines = ""
let idx = 0
while idx < len(b:currentFileVars)
let var = b:currentFileVars[idx]
let varName = toupper(var.name[0]). var.name[1:]
let lines = lines. "\n". "g". idx. " --> ". var.type . " get". varName . "()"
if !var.final
let lines = lines. "\n". "s". idx. " --> ". "set". varName . "(". var.type . " ". var.name. ")"
endif
let lines = lines. "\n"
let idx += 1
endwhile
silent put = lines
call cursor(contentLine + 1, 0)
endfunction
function! javacomplete#generators#Accessor(...)
let s:ti = javacomplete#collector#DoGetClassInfo('this')
call <SID>generateAccessors(a:000)
endfunction
function! s:AddAccessor(map, result, var, declaration, type)
let method = g:JavaComplete_Templates[a:type]
let mods = "public"
if a:var.static
let mods = mods . " static"
let accessor = a:var.className
else
let accessor = 'this'
endif
let method = substitute(method, '$type', a:var.type, 'g')
let method = substitute(method, '$varname', a:var.name, 'g')
let method = substitute(method, '$funcname', a:declaration, 'g')
let method = substitute(method, '$modifiers', mods, 'g')
let method = substitute(method, '$accessor', accessor, 'g')
let begin = len(a:result)
call add(a:result, '')
for line in split(method, '\n')
call add(a:result, line)
endfor
let end = len(a:result)
call add(a:map, [begin, end])
endfunction
function! s:GetVariable(className, def)
let var = {
\ 'name': a:def.name,
\ 'type': a:def.t,
\ 'className': a:className,
\ 'static': javacomplete#util#IsStatic(a:def.m),
\ 'final': javacomplete#util#CheckModifier(a:def.m, g:JC_MODIFIER_FINAL),
\ 'isArray': a:def.t =~# g:RE_ARRAY_TYPE}
let varName = toupper(var.name[0]). var.name[1:]
for def in get(s:ti, 'defs', [])
if get(def, 'tag', '') == 'METHODDEF'
if stridx(get(def, 'd', ''), var.type. ' get'. varName. '()') > -1
let var.getter = 'get'. varName. '()'
break
endif
endif
endfor
return var
endfunction
function! s:CreateAccessors(map, result, var, cmd)
let varName = toupper(a:var.name[0]). a:var.name[1:]
if !a:var.final && stridx(a:cmd, 's') > -1
call s:AddAccessor(a:map, a:result, a:var, "set". varName, 'setter')
endif
if stridx(a:cmd, 'g') > -1
call s:AddAccessor(a:map, a:result, a:var, "get". varName, 'getter')
endif
endfunction
function! <SID>generateAccessors(...)
let result = []
let locationMap = []
if bufname('%') == "__AccessorsBuffer__"
call s:Log("generate accessor for selected fields")
let currentBuf = getline(1,'$')
for line in currentBuf
if line =~ '^\(g\|s\)[0-9]\+.*'
let cmd = line[0]
let idx = line[1:stridx(line, ' ')-1]
let var = b:currentFileVars[idx]
call s:CreateAccessors(locationMap, result, var, cmd)
endif
endfor
execute "bwipeout!"
else
call s:Log("generate accessor for fields under cursor")
if mode() == 'n'
let currentLines = [line('.') - 1]
elseif mode() == 'v'
let [lnum1, col1] = getpos("'<")[1:2]
let [lnum2, col2] = getpos("'>")[1:2]
let currentLines = range(lnum1 - 1, lnum2 - 1)
else
let currentLines = []
endif
for d in get(s:ti, 'defs', [])
if get(d, 'tag', '') == 'VARDEF'
let line = java_parser#DecodePos(d.pos).line
if has_key(d, 'endpos')
let endline = java_parser#DecodePos(d.endpos).line
else
let endline = line
endif
for l in currentLines
if l >= line && l <= endline
let cmd = len(a:1) > 0 ? a:1[0] : 'sg'
let var = s:GetVariable(s:ti.name, d)
call s:CreateAccessors(locationMap, result, var, cmd)
endif
endfor
endif
endfor
endif
call s:InsertResults(s:FilterExistedMethods(locationMap, result))
endfunction
function! s:FilterExistedMethods(locationMap, result)
let resultMethods = []
for def in s:GetNewMethodsDefinitions(a:result)
if !empty(s:CheckImplementationExistense(s:ti, [], def))
continue
endif
for m in a:locationMap
if m[0] <= def.beginline && m[1] >= def.endline
call extend(resultMethods, a:result[m[0] : m[1] -1])
break
endif
endfor
endfor
return resultMethods
endfunction
" create temporary buffer with class declaration, then parse it to get new
" methods definitions.
function! s:GetNewMethodsDefinitions(declarations)
let n = bufwinnr("__tmp_buffer__")
if n != -1
execute "bwipeout!"
endif
silent! split __tmp_buffer__
let result = ['class Tmp {']
call extend(result, a:declarations)
call add(result, '}')
call append(0, result)
let tmpClassInfo = javacomplete#collector#DoGetClassInfo('this', '__tmp_buffer__')
let defs = []
for def in get(tmpClassInfo, 'defs', [])
if get(def, 'tag', '') == 'METHODDEF'
let def.beginline = java_parser#DecodePos(def.pos).line
let def.endline = java_parser#DecodePos(def.body.endpos).line
call add(defs, def)
endif
endfor
execute "bwipeout!"
return defs
endfunction
function! s:InsertResults(result, ...)
if len(a:result) > 0
let positionType = a:0 > 0 && len(a:1) > 0 ? a:1 : 'END'
if positionType == 'END'
call s:InsertAtTheEndOfTheClass(a:result)
return
endif
call s:Log(a:result)
call append(0, a:result)
silent execute "normal! dd"
silent execute "normal! =G"
endif
endfunction
function! s:InsertAtTheEndOfTheClass(result)
let result = a:result
let t = javacomplete#collector#CurrentFileInfo()
let contentLine = line('.')
let currentCol = col('.')
let posResult = {}
for clazz in values(t)
if contentLine > clazz.pos[0] && contentLine <= clazz.endpos[0]
let posResult[clazz.endpos[0] - clazz.pos[0]] = clazz.endpos
endif
endfor
let saveCursor = getpos('.')
call s:Log(posResult)
if len(posResult) > 0
let pos = posResult[min(keys(posResult))]
let endline = pos[0]
if pos[1] > 1 && !empty(javacomplete#util#Trim(getline(pos[0])[:pos[1] - 2]))
let endline += 1
call cursor(pos[0], pos[1])
execute "normal! i\r"
endif
elseif has_key(s:, 'ti') && has_key(s:ti, 'endpos')
let endline = java_parser#DecodePos(s:ti.endpos).line
else
call s:Log("cannot find `endpos` [InsertResult]")
return
endif
if empty(javacomplete#util#Trim(getline(endline - 1)))
if empty(result[0])
let result = result[1:]
endif
elseif !empty(result[0])
call insert(result, '', 0)
endif
call append(endline - 1, result)
call cursor(endline - 1, 1)
silent execute "normal! =G"
if has('saveCursor')
call setpos('.', saveCursor)
endif
endfunction
" vim:set fdm=marker sw=2 nowrap: