" Author: Eric Van Dewoestine " " Description: {{{ " " License: " " Copyright (C) 2005 - 2014 Eric Van Dewoestine " " This program is free software: you can redistribute it and/or modify " it under the terms of the GNU General Public License as published by " the Free Software Foundation, either version 3 of the License, or " (at your option) any later version. " " This program is distributed in the hope that it will be useful, " but WITHOUT ANY WARRANTY; without even the implied warranty of " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " GNU General Public License for more details. " " You should have received a copy of the GNU General Public License " along with this program. If not, see . " " }}} " Global Variables {{{ if !exists('g:EclimTodoSearchPattern') let g:EclimTodoSearchPattern = '\(\\|\\)\c' endif if !exists('g:EclimTodoSearchExtensions') let g:EclimTodoSearchExtensions = [ \ 'css', \ 'html', \ 'java', \ 'js', \ 'jsp', \ 'php', \ 'py', \ 'rb', \ 'sql', \ 'xml', \ ] endif if !exists('g:EclimProjectStatusLine') let g:EclimProjectStatusLine = '${name}' endif " }}} " Script Variables {{{ let s:command_create = '-command project_create -f ""' let s:command_create_name = ' -p ""' let s:command_create_natures = ' -n ' let s:command_create_depends = ' -d ' let s:command_import = '-command project_import -f ""' let s:command_delete = '-command project_delete -p ""' let s:command_rename = '-command project_rename -p "" -n ""' let s:command_move = '-command project_move -p "" -d ""' let s:command_refresh = '-command project_refresh -p ""' let s:command_refresh_file = \ '-command project_refresh_file -p "" -f ""' let s:command_build = '-command project_build -p ""' let s:command_projects = '-command projects' let s:command_project_list = '-command project_list' let s:command_project_by_resource = '-command project_by_resource -f ""' let s:command_project_info = '-command project_info -p ""' let s:command_project_settings = '-command project_settings -p ""' let s:command_project_setting = '-command project_setting -p "" -s ' let s:command_project_update = '-command project_update -p ""' let s:command_update = '-command project_update -p "" -s ""' let s:command_open = '-command project_open -p ""' let s:command_close = '-command project_close -p ""' let s:command_nature_aliases = '-command project_nature_aliases' let s:command_natures = '-command project_natures' let s:command_nature_add = \ '-command project_nature_add -p "" -n ""' let s:command_nature_remove = \ '-command project_nature_remove -p "" -n ""' let s:workspace_projects = {} " }}} function! eclim#project#util#ClearProjectsCache() " {{{ " Flush the cached list of projects. let s:workspace_projects = {} endfunction " }}} function! eclim#project#util#ProjectCD(scope) " {{{ " Change the current working directory to the current project root. let dir = eclim#project#util#GetCurrentProjectRoot() if a:scope == 0 exec 'cd ' . escape(dir, ' ') elseif a:scope == 1 exec 'lcd ' . escape(dir, ' ') endif endfunction " }}} function! eclim#project#util#ProjectCreate(args) " {{{ let args = eclim#util#ParseCmdLine(a:args) let folder = fnamemodify(expand(args[0]), ':p') let folder = substitute(folder, '\', '/', 'g') if has('win32unix') let folder = eclim#cygwin#WindowsPath(folder) endif let command = substitute(s:command_create, '', folder, '') let name = substitute(a:args, '.* -p\s\+\(.\{-}\)\(\s\+-\(d\|n\)\>.*\|$\)', '\1', '') if name != a:args let command .= substitute(s:command_create_name, '', name, '') endif let natureIds = [] let natures = substitute(a:args, '.* -n\s\+\(.\{-}\)\(\s\+-\(d\|p\)\>.*\|$\)', '\1', '') if natures != a:args let natures = substitute(natures, '\s\+', ',', 'g') let natureIds = split(natures, ',') let command .= substitute(s:command_create_natures, '', natures, '') endif let depends = substitute(a:args, '.* -d\s\+\(.\{-}\)\(\s\+-\(n\|p\)\>.*\|$\)', '\1', '') if depends != a:args let depends = substitute(depends, '\s\+', ',', 'g') let command .= substitute(s:command_create_depends, '', depends, '') endif " execute any pre-project creation hooks let hook_result = s:ProjectNatureHooks(natureIds, 'ProjectCreatePre', [folder]) if type(hook_result) == g:NUMBER_TYPE && !hook_result return elseif type(hook_result) == g:STRING_TYPE && len(hook_result) let command .= ' -a ' . hook_result endif let result = eclim#Execute(command, {'dir': folder}) if result != '0' call eclim#util#Echo(result) call eclim#project#util#ClearProjectsCache() endif " execute any post-project creation hooks call s:ProjectNatureHooks(natureIds, 'ProjectCreatePost', [folder]) endfunction " }}} function! s:ProjectNatureHooks(natureIds, hookName, args) " {{{ let results = '' for nature in a:natureIds if nature == 'none' continue endif exec 'runtime autoload/eclim/' . nature . '/project.vim' try let l:Hook = function('eclim#' . nature . '#project#' . a:hookName) let result = call(l:Hook, a:args) if type(result) == g:NUMBER_TYPE && !result return result endif if type(result) == g:STRING_TYPE if len(results) let results .= ' ' endif let results .= result endif catch /E\(117\|700\):.*/ " ignore endtry endfor if len(results) return results endif return 1 endfunction " }}} function! eclim#project#util#ProjectImport(arg) " {{{ let folder = fnamemodify(expand(a:arg), ':p') let folder = substitute(folder, '\', '/', 'g') if has('win32unix') let folder = eclim#cygwin#WindowsPath(folder) endif let command = substitute(s:command_import, '', folder, '') let naturesDict = {} for [key, value] in items(eclim#project#util#GetNatureAliasesDict()) let naturesDict[value[-1]] = key endfor let natureIds = [] let dotproject = folder . '/' . '.project' if filereadable(dotproject) for line in readfile(dotproject) if line =~ '^\s*' let id = substitute(line, '.*\\(.*\).*', '\1', '') if has_key(naturesDict, id) call add(natureIds, naturesDict[id]) endif endif endfor if !s:ProjectNatureHooks(natureIds, 'ProjectImportPre', [folder]) return endif endif let result = eclim#Execute(command, {'dir': folder}) if result != '0' let project = eclim#project#util#GetProject(folder) if !len(natureIds) let natureIds = eclim#project#util#GetProjectNatureAliases( \ get(project, 'name', '')) endif call s:ProjectNatureHooks(natureIds, 'ProjectImportPost', [project]) call eclim#util#Echo(result) call eclim#project#util#ClearProjectsCache() endif endfunction " }}} function! eclim#project#util#ProjectDelete(name) " {{{ let command = substitute(s:command_delete, '', a:name, '') let result = eclim#Execute(command, {'project': a:name}) if result != '0' call eclim#util#Echo(result) call eclim#project#util#ClearProjectsCache() endif endfunction " }}} function! eclim#project#util#ProjectRename(args) " {{{ let args = eclim#util#ParseCmdLine(a:args) if len(args) == 1 if !eclim#project#util#IsCurrentFileInProject() return endif let project = eclim#project#util#GetCurrentProjectName() let name = args[0] else let project = args[0] let name = args[1] endif if exists('g:EclimProjectRenamePrompt') && !g:EclimProjectRenamePrompt let response = 1 else let response = eclim#util#PromptConfirm( \ printf("Rename project '%s' to '%s'", project, name), \ g:EclimHighlightInfo) endif if response == 1 let command = s:command_rename let command = substitute(command, '', project, '') let command = substitute(command, '', name, '') call s:ProjectMove(project, name, command) endif endfunction " }}} function! eclim#project#util#ProjectMove(args) " {{{ let args = eclim#util#ParseCmdLine(a:args) if len(args) == 1 if !eclim#project#util#IsCurrentFileInProject() return endif let project = eclim#project#util#GetCurrentProjectName() let dir = args[0] else let project = args[0] let dir = args[1] endif let dir = expand(dir) let dir = substitute(fnamemodify(dir, ':p'), '\', '/', 'g') if has('win32unix') let dir = eclim#cygwin#WindowsPath(dir) endif if exists('g:EclimProjectMovePrompt') && !g:EclimProjectMovePrompt let response = 1 else let response = eclim#util#PromptConfirm( \ printf("Move project '%s' to '%s'", project, dir), \ g:EclimHighlightInfo) endif if response == 1 let command = s:command_move let command = substitute(command, '', project, '') let command = substitute(command, '', dir, '') call s:ProjectMove(project, project, command) endif endfunction " }}} function! s:ProjectMove(oldname, newname, command) " {{{ let cwd = substitute(getcwd(), '\', '/', 'g') let cwd_return = 1 let oldpath = eclim#project#util#GetProjectRoot(a:oldname) let curwin = winnr() try " cd to home to avoid folder renaming issues on windows. cd ~ " turn off swap files temporarily to avoid issues with folder renaming. let bufend = bufnr('$') let bufnum = 1 while bufnum <= bufend if bufexists(bufnum) call setbufvar(bufnum, 'save_swapfile', getbufvar(bufnum, '&swapfile')) call setbufvar(bufnum, '&swapfile', 0) endif let bufnum = bufnum + 1 endwhile " write all changes before moving wall let result = eclim#Execute(a:command, {'project': a:oldname}) if result == "0" return endif call eclim#project#util#ClearProjectsCache() let newpath = eclim#project#util#GetProjectRoot(a:newname) if cwd =~ '^' . oldpath exec 'cd ' . substitute(cwd, oldpath, newpath, '') let cwd_return = 0 endif " reload files affected by the project renaming let bufnum = 1 while bufnum <= bufend if buflisted(bufnum) let path = substitute(fnamemodify(bufname(bufnum), ':p'), '\', '/', 'g') if path =~ '^' . oldpath let path = substitute(path, oldpath, newpath, '') if filereadable(path) let winnr = bufwinnr(bufnum) if winnr != -1 exec winnr . 'winc w' exec 'edit ' . eclim#util#Simplify(path) endif exec 'bdelete ' . bufnum endif endif endif let bufnum = bufnum + 1 endwhile finally exec curwin 'winc w' if cwd_return exec 'cd ' . escape(cwd, ' ') endif " re-enable swap files let bufnum = 1 while bufnum <= bufend if bufexists(bufnum) let save_swapfile = getbufvar(bufnum, 'save_swapfile') if save_swapfile != '' call setbufvar(bufnum, '&swapfile', save_swapfile) endif endif let bufnum = bufnum + 1 endwhile endtry call eclim#util#Echo(result) endfunction " }}} function! eclim#project#util#ProjectRefreshAll() " {{{ call eclim#project#util#ClearProjectsCache() let projects = eclim#project#util#GetProjectNames() for project in projects call eclim#project#util#ProjectRefresh(project, 0) endfor call eclim#util#Echo('Done.') endfunction " }}} function! eclim#project#util#ProjectRefresh(args, ...) " {{{ " Optional args: " clear_cache: Clear the in memory project cache first if a:0 == 0 || a:000[0] == 1 call eclim#project#util#ClearProjectsCache() endif if a:args != '' let projects = eclim#util#ParseCmdLine(a:args) else if !eclim#project#util#IsCurrentFileInProject() return endif let project = eclim#project#util#GetCurrentProjectName() let projects = [project] endif for project in projects call eclim#util#Echo("Updating project '" . project . "'...") let command = substitute(s:command_refresh, '', project, '') call eclim#util#Echo(eclim#Execute(command, {'project': project})) endfor if len(projects) > 1 call eclim#util#Echo('Done.') endif endfunction " }}} function! eclim#project#util#ProjectBuild(...) " {{{ " Option args: " project: The name of the project to build (use the current project " otherwise) let project = a:0 > 0 ? a:1 : '' if project == '' if !eclim#project#util#IsCurrentFileInProject() return endif let project = eclim#project#util#GetCurrentProjectName() endif call eclim#util#Echo("Building project '" . project . "'...") let command = substitute(s:command_build, '', project, '') let result = eclim#Execute(command, {'project': project}) call eclim#project#problems#ProblemsUpdate('build') call eclim#util#Echo(result) endfunction " }}} function! eclim#project#util#ProjectInfo(project) " {{{ let project = a:project if project == '' let project = eclim#project#util#GetCurrentProjectName() endif if project == '' call eclim#project#util#UnableToDetermineProject() return endif let command = substitute(s:command_project_info, '', project, '') let result = eclim#Execute(command, {'project': project}) if type(result) == g:DICT_TYPE let output = \ 'Name: ' . result.name . "\n" . \ 'Path: ' . result.path . "\n" . \ 'Workspace: ' . result.workspace . "\n" . \ 'Open: ' . (result.open ? 'true' : 'false') if has_key(result, 'natures') let output .= "\n" . 'Natures: ' . join(result.natures, ', ') endif if has_key(result, 'depends') let output .= "\n" . 'Depends On: ' . join(result.depends, ', ') endif if has_key(result, 'referenced') let output .= "\n" . 'Referenced By: ' . join(result.referenced, ', ') endif call eclim#util#Echo(output) elseif type(result) == g:STRING_TYPE call eclim#util#Echo(result) endif endfunction " }}} function! eclim#project#util#ProjectStatusLine() " {{{ " Includes status information for the current file to VIM status " don't ever display errors since this is called from the user's status " line. silent! let project = eclim#project#util#GetProject(expand('%:p')) if !empty(project) let status = g:EclimProjectStatusLine while status =~ '\${\w\+}' let m = matchstr(status, '\${\w\+}') let key = substitute(m, '^\${\(\w\+\)}', '\1', '') let val = '' if has_key(project, key) let type = type(project[key]) if type == 1 let val = project[key] elseif type == 3 let val = join(project[key], ',') else let val = string(project[key]) endif endif let status = substitute(status, m, val, 'g') endwhile return status endif return '' endfunction " }}} function! eclim#project#util#ProjectOpen(name) " {{{ let name = a:name if name == '' if !eclim#project#util#IsCurrentFileInProject() return endif let name = eclim#project#util#GetCurrentProjectName() endif let command = substitute(s:command_open, '', name, '') let result = eclim#Execute(command, {'project': name}) if result != '0' call eclim#util#Echo(result) call eclim#project#util#ClearProjectsCache() endif endfunction " }}} function! eclim#project#util#ProjectClose(name) " {{{ let name = a:name if name == '' if !eclim#project#util#IsCurrentFileInProject() return endif let name = eclim#project#util#GetCurrentProjectName() endif let command = substitute(s:command_close, '', name, '') let result = eclim#Execute(command, {'project': name}) if result != '0' call eclim#util#Echo(result) endif endfunction " }}} function! eclim#project#util#ProjectList(workspace) " {{{ let projects = eclim#Execute(s:command_project_list, {'workspace': a:workspace}) if len(projects) == 0 call eclim#util#Echo("No projects.") endif if type(projects) != g:LIST_TYPE return endif let pad = 0 for project in projects let pad = len(project.name) > pad ? len(project.name) : pad endfor let output = [] for project in projects call add(output, \ eclim#util#Pad(project.name, pad) . ' - ' . \ (project.open ? ' open ' : 'closed') . ' - ' . \ project.path) endfor call eclim#util#Echo(join(output, "\n")) endfunction " }}} function! eclim#project#util#ProjectNatures(project) " {{{ " Prints nature info of one or all projects. if !eclim#EclimAvailable() return endif let command = s:command_natures if a:project != '' let command .= ' -p "' . a:project . '"' let projects = eclim#Execute(command, {'project': a:project}) if type(projects) != g:LIST_TYPE return endif else let projects = [] let instances = eclim#client#nailgun#GetEclimdInstances() for workspace in keys(instances) let results = eclim#Execute(command, {'instance': instances[workspace]}) if type(results) != g:LIST_TYPE continue endif let projects += results endfor endif if len(projects) == 0 call eclim#util#Echo("No projects.") endif let pad = 0 for project in projects let pad = len(project.name) > pad ? len(project.name) : pad endfor let output = [] for project in projects call add(output, \ eclim#util#Pad(project.name, pad) . ' - ' . join(project.natures, ', ')) endfor call eclim#util#Echo(join(output, "\n")) endfunction " }}} function! eclim#project#util#ProjectNatureModify(command, args) " {{{ " Modifies one or more natures for the specified project. let args = eclim#util#ParseCmdLine(a:args) let project = args[0] if eclim#project#util#GetProjectRoot(project) == '' call eclim#util#EchoError('Project not found: ' . project) return endif let natures = args[1:] if len(natures) == 0 call eclim#util#EchoError('Please supply at least one nature alias.') return else let aliases = eclim#project#util#GetNatureAliasesDict() let invalid = [] for nature in natures if !has_key(aliases, nature) call add(invalid, nature) endif endfor if len(invalid) > 0 call eclim#util#EchoError( \ 'One or more unrecognized nature aliases: ' . join(invalid, ',')) return endif endif let command = a:command == 'add' ? s:command_nature_add : s:command_nature_remove let command = substitute(command, '', project, '') let command = substitute(command, '', join(natures, ','), '') if a:command == 'add' let hook_result = s:ProjectNatureHooks(natures, 'ProjectNatureAddPre', [project]) if type(hook_result) == g:NUMBER_TYPE && !hook_result return elseif type(hook_result) == g:STRING_TYPE && len(hook_result) let command .= ' -a ' . hook_result endif endif let result = eclim#Execute(command, {'project': project}) if result != '0' if a:command == 'add' call s:ProjectNatureHooks(natures, 'ProjectNatureAddPost', [project]) endif call eclim#util#Echo(result) endif endfunction " }}} function! eclim#project#util#ProjectSettings(project) " {{{ " Opens a window that can be used to edit a project's settings. let project = a:project if project == '' let project = eclim#project#util#GetCurrentProjectName() endif if project == '' call eclim#project#util#UnableToDetermineProject() return endif let command = substitute(s:command_project_settings, '', project, '') let settings = eclim#Execute(command, {'project': project}) if type(settings) != g:LIST_TYPE return endif let content = ['# Settings for project: ' . project, ''] let path = '' for setting in settings if setting.path != path if path != '' let content += ['# }', ''] endif let path = setting.path call add(content, '# ' . path . ' {') endif let description = split(setting.description, '\n') let content += map(description, "'\t# ' . v:val") call add(content, "\t" . setting.name . '=' . setting.value) endfor if path != '' call add(content, '# }') endif call eclim#util#TempWindow(project . "_settings", content) exec "lcd " . escape(eclim#project#util#GetProjectRoot(project), ' ') setlocal buftype=acwrite setlocal filetype=jproperties setlocal noreadonly setlocal modifiable setlocal foldmethod=marker setlocal foldmarker={,} setlocal foldlevel=0 let b:project = project augroup project_settings autocmd! BufWriteCmd autocmd BufWriteCmd call SaveSettings() augroup END endfunction " }}} function! eclim#project#util#ProjectUpdate() " {{{ " Executes a project update which may also validate nature specific resource " file. let name = eclim#project#util#GetCurrentProjectName() if name == '' call eclim#util#EchoError('Unable to determine the project.') return endif let command = substitute(s:command_project_update, '', name, '') let result = eclim#Execute(command) if type(result) == g:LIST_TYPE && len(result) > 0 let errors = eclim#util#ParseLocationEntries( \ result, g:EclimValidateSortResults) call eclim#util#SetLocationList(errors) else call eclim#util#ClearLocationList() call eclim#util#Echo(result) endif endfunction " }}} function! eclim#project#util#ProjectGrep(command, args) " {{{ " Executes the supplied vim grep command with the specified pattern against " one or more file patterns. if !eclim#project#util#IsCurrentFileInProject() return endif let project = eclim#project#util#GetProject(expand('%:p')) let tail = substitute(a:args, '\(.\).\{-}\1\s\(.*\)', '\2', '') let pattern = substitute(a:args, '\(.*\)\s\+\M' . tail . '\m$', '\1', '') let cmd = a:command let acd = &autochdir set noautochdir try if pattern != a:args && tail != a:args && tail != '' let files = eclim#util#ParseArgs(tail) let paths = '' for file in files if paths != '' let paths .= ' ' endif let paths .= escape(project.path, ' ') . '/' . file endfor let links = get(project, 'links', {}) if len(links) for link in values(links) for file in files let paths .= ' ' . escape(link, ' ') . '/' . file endfor endfor endif silent exec a:command . ' ' . pattern . ' ' . paths else " let vim generate the proper error silent exec a:command . ' ' . a:args endif catch /E480/ " no results found catch /.*/ call eclim#util#EchoError(v:exception) return finally let &autochdir = acd " force quickfix / location list signs to update. call eclim#display#signs#Update() endtry let numresults = len(a:command =~ '^l' ? getloclist(0) : getqflist()) if numresults == 0 call eclim#util#EchoInfo('No results found.') endif endfunction " }}} function! eclim#project#util#ProjectTab(project) " {{{ " Opens a new tab with the project tree and tab relative working directory for " the specified project. let project = a:project let names = eclim#project#util#GetProjectNames() if index(names, project) == -1 let is_project = 0 let dir = expand(project, ':p') if !isdirectory(dir) if eclim#EclimAvailable(0) call eclim#util#EchoError("No project '" . project . "' found.") endif return endif let project = fnamemodify(substitute(dir, '/$', '', ''), ':t') else let is_project = 1 let dir = eclim#project#util#GetProjectRoot(project) endif if exists('t:eclim_project') || \ winnr('$') > 1 || expand('%') != '' || \ &modified || line('$') != 1 || getline(1) != '' tablast | tabnew endif let t:eclim_project = project call eclim#common#util#Tcd(dir) if g:EclimProjectTabTreeAutoOpen if is_project call eclim#project#tree#ProjectTree(project) else call eclim#project#tree#ProjectTree(dir) endif else call eclim#util#Echo('ProjectTab ' . project . ' cwd: ' . dir) endif endfunction " }}} function! eclim#project#util#Todo() " {{{ " Show the todo tags of the curent file in the location list. if !eclim#project#util#IsCurrentFileInProject() return endif let path = expand('%:p') silent! exec 'lvimgrep /' . g:EclimTodoSearchPattern . '/gj ' . path if !empty(getloclist(0)) exec 'lopen ' . g:EclimLocationListHeight else call eclim#util#Echo('No Results found') endif endfunction " }}} function! eclim#project#util#ProjectTodo() " {{{ " Show the todo tags of the whole project in the location list. if !eclim#project#util#IsCurrentFileInProject() return endif if len(g:EclimTodoSearchExtensions) == 0 endif let project = eclim#project#util#GetProject(expand('%:p')) let paths = '' for ext in g:EclimTodoSearchExtensions if paths != '' let paths .= ' ' endif let paths .= escape(project.path, ' ') . '/**/*' . ext endfor let links = get(project, 'links', {}) if len(links) for link in values(links) for ext in g:EclimTodoSearchExtensions let paths .= ' ' . escape(link, ' ') . '/**/*' . ext endfor endfor endif silent! exec 'lvimgrep /' . g:EclimTodoSearchPattern . '/gj ' . paths if !empty(getloclist(0)) exec 'lopen ' . g:EclimLocationListHeight else call eclim#util#Echo('No Results found') endif endfunction " }}} function! s:SaveSettings() " {{{ call eclim#SaveSettings(s:command_update, b:project) endfunction " }}} function! eclim#project#util#GetCurrentProjectName() " {{{ " Gets the project name that the current file is in. let project = eclim#project#util#GetProject(expand('%:p')) return len(project) > 0 ? project.name : '' endfunction " }}} function! eclim#project#util#GetCurrentProjectRoot(...) " {{{ " Gets the project root dir for the project that the current or supplied " file is in. let path = len(a:000) > 0 ? a:000[0] : expand('%:p') let project = eclim#project#util#GetProject(path) return len(project) > 0 ? project.path : '' endfunction " }}} function! eclim#project#util#GetProjectWorkspace(name) " {{{ " Gets the workspace that a project belongs to. " ensure s:workspace_projects is initialized call eclim#project#util#GetProjects() " loop through each workspace since the same project name could be used in " more than one workspace. let workspaces = [] for [workspace, projects] in items(s:workspace_projects) for p in projects if p.name == a:name call add(workspaces, workspace) break endif endfor endfor if len(workspaces) > 1 return workspaces endif return len(workspaces) ? workspaces[0] : '' endfunction " }}} function! eclim#project#util#GetProjectRelativeFilePath(...) " {{{ " Gets the project relative path for the current or supplied file. " Optional args: " file: get the relative path for this file instead of the current one. if exists('b:eclim_file') return b:eclim_file endif let file = a:0 == 0 ? expand('%:p') : a:1 let project = eclim#project#util#GetProject(file) if !len(project) return '' endif let file = substitute(fnamemodify(file, ':p'), '\', '/', 'g') let pattern = '\(/\|$\)' if has('win32') || has('win64') let pattern .= '\c' endif let result = substitute(file, get(project, 'path', '') . pattern, '', '') " handle file in linked folder if result == file for name in keys(get(project, 'links', {})) if file =~ '^' . project.links[name] . pattern let result = substitute(file, project.links[name], name, '') endif endfor endif if result != file && result =~ '^/' let result = result[1:] endif return result endfunction " }}} function! eclim#project#util#GetProjects() " {{{ " Returns a list of project dictionaries containing the following properties: " workspace: The path of the workspace the project belongs to. " name: The name of the project. " path: The root path of the project. " links: List of linked paths. let instances = eclim#client#nailgun#GetEclimdInstances() if keys(s:workspace_projects) != keys(instances) let s:workspace_projects = {} for workspace in keys(instances) let instance = instances[workspace] let results = eclim#Execute( \ s:command_projects, {'instance': instance}) if type(results) != g:LIST_TYPE continue endif if has('win32unix') " gather paths to translate let winpaths = [] for project in results call add(winpaths, project['path']) if has_key(project, 'links') for key in sort(keys(project['links'])) call add(winpaths, project['links'][key]) endfor endif endfor let cygpaths = eclim#cygwin#CygwinPath(winpaths) " update each project with the cygwin version of its paths let index = 0 for project in results let project['path'] = cygpaths[index] let index += 1 if has_key(project, 'links') for key in sort(keys(project['links'])) let project['links'][key] = cygpaths[index] let index += 1 endfor endif endfor endif for project in results let project['workspace'] = instance.workspace endfor let s:workspace_projects[instance.workspace] = results unlet results endfor endif let all = [] for projects in values(s:workspace_projects) let all += copy(projects) endfor return all endfunction " }}} function! eclim#project#util#GetProject(path) " {{{ " if a [No Name] buffer, use the current working directory. let path = a:path != '' ? a:path : getcwd() let path = substitute(fnamemodify(path, ':p'), '\', '/', 'g') let pattern = '\(/\|$\)' if has('win32') || has('win64') let pattern .= '\c' endif let projects = eclim#project#util#GetProjects() " sort projects depth wise by path to properly support nested projects. call sort(projects, 's:ProjectSortPathDepth') for project in projects if path =~ '^' . project.path . pattern return project endif if has_key(project, 'link') && path =~ '^' . project.link . pattern return project endif " check linked folders for name in keys(get(project, 'links', {})) if path =~ '^' . project.links[name] . pattern return project endif endfor endfor " project not found by path, fallback to buffer local variable if exists('b:eclim_project') for project in projects if project.name == b:eclim_project return project endif endfor endif return {} endfunction " }}} function! s:ProjectSortPathDepth(p1, p2) " {{{ return len(a:p2.path) - len(a:p1.path) endfunction " }}} function! eclim#project#util#GetProjectDirs() " {{{ " Gets list of all project root directories. return map(eclim#project#util#GetProjects(), 'v:val.path') endfunction " }}} function! eclim#project#util#GetProjectNames(...) " {{{ " Gets list of all project names, with optional filter by the supplied nature " alias. " Option args: " nature: The nature alias to filter projects by " filter by nature if a:0 > 0 && a:1 != '' let projects = [] let command = s:command_project_list . ' -n ' . a:1 let instances = eclim#client#nailgun#GetEclimdInstances() for workspace in keys(instances) let results = eclim#Execute(command, {'instance': instances[workspace]}) if type(results) != g:LIST_TYPE continue endif let projects += results endfor let names = map(projects, "v:val.name") else let names = map(eclim#project#util#GetProjects(), 'v:val.name') endif return eclim#util#ListDedupe(sort(names)) endfunction " }}} function! eclim#project#util#GetProjectNatureAliases(...) " {{{ " Gets list of all project nature aliases or a list of aliases associated with " a project if the project name is supplied. " Optional args: " project: the project to get natures aliases from. if a:0 > 0 && a:1 != '' let command = s:command_natures . ' -p "' . a:1 . '"' let result = eclim#Execute(command) if type(result) != g:LIST_TYPE || len(result) == 0 return [] endif return result[0]['natures'] endif let aliases = eclim#Execute(s:command_nature_aliases) if type(aliases) != g:LIST_TYPE return [] endif return aliases endfunction " }}} function! eclim#project#util#GetNatureAliasesDict() " {{{ " Gets a dict of all natures aliases where the alias is the key and the nature " id is the value. let aliases = eclim#Execute(s:command_nature_aliases . ' -m') if type(aliases) != g:DICT_TYPE return {} endif return aliases endfunction " }}} function! eclim#project#util#GetProjectRoot(name) " {{{ " Gets the project root dir for the supplied project name. let project = {} for p in eclim#project#util#GetProjects() if p.name == a:name let project = p break endif endfor return get(project, 'path', '') endfunction " }}} function! eclim#project#util#GetProjectSetting(setting) " {{{ " Gets a project setting from eclim. Returns '' if the setting does not " exist, 0 if not in a project or an error occurs communicating with the " server. if !eclim#project#util#IsCurrentFileInProject() return endif let project = eclim#project#util#GetCurrentProjectName() let command = s:command_project_setting let command = substitute(command, '', project, '') let command = substitute(command, '', a:setting, '') let result = eclim#Execute(command) if result == '0' return result endif if result == '' call eclim#util#EchoWarning("Setting '" . a:setting . "' does not exist.") endif return result endfunction " }}} function! eclim#project#util#SetProjectSetting(setting, value) " {{{ if !eclim#project#util#IsCurrentFileInProject() return endif let project = eclim#project#util#GetCurrentProjectName() let command = s:command_project_setting let command = substitute(command, '', project, '') let command = substitute(command, '', a:setting, '') let command .= ' -v "' . a:value . '"' call eclim#Execute(command) endfunction " }}} function! eclim#project#util#IsCurrentFileInProject(...) " {{{ " Determines if the current file is in a project directory. " Accepts an optional arg that determines if a message is displayed to the " user if the file is not in a project(defaults to 1, to display the " message). " Optional args: " echo_error (default: 1): when non-0, echo an error to the user if project " could not be determined. let echo = a:0 ? a:1 : 1 if !echo silent let project = eclim#project#util#GetCurrentProjectName() else let project = eclim#project#util#GetCurrentProjectName() endif if project == '' " if eclimd isn't available, then that could be the reason the project " couldn't be determined, so don't hide that message with this one. if echo && eclim#EclimAvailable(0) call eclim#util#EchoError('Unable to determine the project. ' . \ 'Check that the current file is in a valid project.') endif return 0 endif return 1 endfunction " }}} function! eclim#project#util#RefreshFileBootstrap() " {{{ " Boostraps a post write autocommand for updating files, which forces a " refresh by the eclim project. The command should only be called as part of " the a BufWritePre autocmd. if eclim#project#util#GetCurrentProjectName() != '' && &modified let refresh = !exists('b:EclimRefreshDisabled') || !b:EclimRefreshDisabled if refresh augroup eclim_refresh_files_bootstrap autocmd! autocmd BufWritePost call eclim#project#util#RefreshFile() augroup END endif endif endfunction " }}} function! eclim#project#util#RefreshFile() " {{{ " Refreshes the current files in eclipse. augroup eclim_refresh_files_bootstrap autocmd! BufWritePost augroup END let project = eclim#project#util#GetCurrentProjectName() let file = eclim#project#util#GetProjectRelativeFilePath() let command = s:command_refresh_file let command = substitute(command, '', project, '') let command = substitute(command, '', file, '') call eclim#Execute(command) endfunction " }}} function! eclim#project#util#UnableToDetermineProject() " {{{ " if eclimd isn't available, then that could be the reason the project " couldn't be determined, so don't hide that message with this one. if eclim#EclimAvailable(0) call eclim#util#EchoError("Unable to determine the project. " . \ "Please specify a project name or " . \ "execute from a valid project directory.") endif endfunction " }}} function! eclim#project#util#CommandCompleteProject(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project names. return eclim#project#util#CommandCompleteProjectByNature( \ a:argLead, a:cmdLine, a:cursorPos, '') endfunction " }}} function! eclim#project#util#CommandCompleteProjectContainsThis(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project names, filtering by those that contain " a file with the same path as the current file, excluding the current " project. let names = eclim#project#util#CommandCompleteProject( \ a:argLead, a:cmdLine, a:cursorPos) let path = eclim#project#util#GetProjectRelativeFilePath() let project = eclim#project#util#GetCurrentProjectName() let projects = eclim#project#util#GetProjects() call filter(names, 'v:val != project && filereadable(eclim#project#util#GetProjectRoot(v:val) . "/" . path)') return names endfunction " }}} function! eclim#project#util#CommandCompleteProjectByNature(argLead, cmdLine, cursorPos, nature) " {{{ " Custom command completion for project names limited by the supplied nature. let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let cmdTail = strpart(a:cmdLine, a:cursorPos) let argLead = substitute(a:argLead, cmdTail . '$', '', '') let projects = eclim#project#util#GetProjectNames(a:nature) if cmdLine !~ '[^\\]\s$' let argLead = escape(escape(argLead, '~'), '~') " remove escape slashes let argLead = substitute(argLead, '\', '', 'g') call filter(projects, 'v:val =~ "^' . argLead . '"') endif call map(projects, 'escape(v:val, " ")') return projects endfunction " }}} function! eclim#project#util#CommandCompleteProjectCreate(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for ProjectCreate args. let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let args = eclim#util#ParseCmdLine(cmdLine) let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] " complete dirs for first arg if cmdLine =~ '^' . args[0] . '\s\+' . escape(argLead, '~.\') . '$' return eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) endif " complete nature aliases if cmdLine =~ '-n\s\+[^-]*$' let aliases = eclim#project#util#GetProjectNatureAliases() " if one alias already supplied complete options as well if cmdLine !~ '-n\s\+$' && argLead == '' let aliases = \ s:CommandCompleteProjectCreateOptions(argLead, a:cmdLine, a:cursorPos) + \ aliases endif if cmdLine !~ '[^\\]\s$' call filter(aliases, 'v:val =~ "^' . escape(escape(argLead, '~.\'), '\') . '"') endif return aliases endif " complete project dependencies if cmdLine =~ '-d\s\+[^-]*$' " if one dependency already supplied complete options as well if cmdLine !~ '-d\s\+$' && argLead == '' let options = \ s:CommandCompleteProjectCreateOptions(argLead, a:cmdLine, a:cursorPos) return options + \ eclim#project#util#CommandCompleteProject(argLead, a:cmdLine, a:cursorPos) endif return eclim#project#util#CommandCompleteProject(argLead, a:cmdLine, a:cursorPos) endif return s:CommandCompleteProjectCreateOptions(argLead, a:cmdLine, a:cursorPos) endfunction " }}} function! s:CommandCompleteProjectCreateOptions(argLead, cmdLine, cursorPos) " {{{ let options = ['-n', '-d', '-p'] if a:cmdLine =~ '\s-n\>' call remove(options, index(options, '-n')) endif if a:cmdLine =~ '\s-d\>' call remove(options, index(options, '-d')) endif if a:cmdLine =~ '\s-p\>' call remove(options, index(options, '-p')) endif return options endfunction " }}} function! eclim#project#util#CommandCompleteProjectMove(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for ProjectMove args. let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let args = eclim#util#ParseCmdLine(cmdLine) let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] " complete dirs for second arg if first arg is a project name if len(args) > 1 && eclim#project#util#GetProjectRoot(args[1]) != '' && \ cmdLine =~ '^' . args[0] . '\s\+' . args[1] . '\s\+' . escape(argLead, '~.\') . '$' return eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) endif " attempt complete project and dir for first arg if cmdLine =~ '^' . args[0] . '\s\+' . escape(argLead, '~.\') . '$' let projects = [] let dirs = eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) if argLead !~ '[~]' let projects = eclim#project#util#CommandCompleteProject( \ argLead, a:cmdLine, a:cursorPos) endif return projects + dirs endif return [] endfunction " }}} function! eclim#project#util#CommandCompleteProjectRelative(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project relative files and directories. let dir = eclim#project#util#GetCurrentProjectRoot() if dir == '' && exists('b:project') let dir = eclim#project#util#GetProjectRoot(b:project) endif if dir == '' return [] endif let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let args = eclim#util#ParseCmdLine(cmdLine) let argLead = cmdLine =~ '\s$' ? '' : (len(args) > 0 ? args[len(args) - 1] : '') let results = split(eclim#util#Glob(dir . '/' . argLead . '*', 1), '\n') call map(results, "substitute(v:val, '\\', '/', 'g')") call map(results, 'isdirectory(v:val) ? v:val . "/" : v:val') call map(results, 'substitute(v:val, dir, "", "")') call map(results, 'substitute(v:val, "^\\(/\\|\\\\\\)", "", "g")') call map(results, "substitute(v:val, ' ', '\\\\ ', 'g')") return eclim#util#ParseCommandCompletionResults(argLead, results) endfunction " }}} function! eclim#project#util#CommandCompleteProjectRelativeDir(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project relative files and directories. let dir = eclim#project#util#GetCurrentProjectRoot() if dir == '' && exists('b:project') let dir = eclim#project#util#GetProjectRoot(b:project) endif if dir == '' return [] endif let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let args = eclim#util#ParseCmdLine(cmdLine) let argLead = cmdLine =~ '\s$' ? '' : (len(args) > 0 ? args[len(args) - 1] : '') let results = split(eclim#util#Glob(dir . '/' . argLead . '*', 1), '\n') call map(results, "substitute(v:val, '\\', '/', 'g')") call filter(results, 'isdirectory(v:val)') call map(results, 'v:val . "/"') call map(results, 'substitute(v:val, dir, "", "")') call map(results, 'substitute(v:val, "^\\(/\\|\\\\\\)", "", "g")') call map(results, "substitute(v:val, ' ', '\\\\ ', 'g')") return eclim#util#ParseCommandCompletionResults(argLead, results) endfunction " }}} function! eclim#project#util#CommandCompleteProjectOrDirectory(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for :ProjectTree/:ProjectTab to complete project names or " directories let projects = [] if a:argLead !~ '[~/]' let projects = eclim#project#util#CommandCompleteProjectByNature( \ a:argLead, a:cmdLine, a:cursorPos, '') endif let dirs = eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) return projects + dirs endfunction " }}} function! eclim#project#util#CommandCompleteAbsoluteOrProjectRelative(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project relative files and directories. let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let args = eclim#util#ParseCmdLine(cmdLine) if len(args) > 0 let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] if argLead =~ '^\(/\|[a-zA-Z]:\)' return eclim#util#CommandCompleteFile(a:argLead, a:cmdLine, a:cursorPos) endif endif return eclim#project#util#CommandCompleteProjectRelative( \ a:argLead, a:cmdLine, a:cursorPos) endfunction " }}} function! eclim#project#util#CommandCompleteAbsoluteOrProjectRelativeDir(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project relative files and directories. let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let args = eclim#util#ParseCmdLine(cmdLine) if len(args) > 0 let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] if argLead =~ '^\(/\|[a-zA-Z]:\)' return eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) endif endif return eclim#project#util#CommandCompleteProjectRelativeDir( \ a:argLead, a:cmdLine, a:cursorPos) endfunction " }}} function! eclim#project#util#CommandCompleteProjectNatureAdd(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project names and natures. return s:CommandCompleteProjectNatureModify( \ a:argLead, a:cmdLine, a:cursorPos, function("s:AddAliases")) endfunction " }}} function! s:AddAliases(allAliases, projectAliases) " {{{ let aliases = a:allAliases call filter(aliases, 'index(a:projectAliases, v:val) == -1') return aliases endfunction " }}} function! eclim#project#util#CommandCompleteProjectNatureRemove(argLead, cmdLine, cursorPos) " {{{ " Custom command completion for project names and natures. return s:CommandCompleteProjectNatureModify( \ a:argLead, a:cmdLine, a:cursorPos, function("s:RemoveAliases")) endfunction " }}} function! s:RemoveAliases(allAliases, projectAliases) " {{{ return a:projectAliases endfunction " }}} function! s:CommandCompleteProjectNatureModify(argLead, cmdLine, cursorPos, aliasesFunc) " {{{ " Custom command completion for project names and natures. let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) let args = eclim#util#ParseCmdLine(cmdLine) let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] " complete dirs for first arg if cmdLine =~ '^' . args[0] . '\s\+' . escape(argLead, '~.\') . '$' return eclim#project#util#CommandCompleteProject(argLead, a:cmdLine, a:cursorPos) endif let allAliases = eclim#project#util#GetProjectNatureAliases() call filter(allAliases, 'v:val != "none"') let projectAliases = eclim#project#util#GetProjectNatureAliases(args[1]) let aliases = a:aliasesFunc(allAliases, projectAliases) if cmdLine !~ '[^\\]\s$' call filter(aliases, 'v:val =~ "^' . argLead . '"') endif call filter(aliases, 'index(args[2:], v:val) == -1') return aliases endfunction " }}} " vim:ft=vim:fdm=marker