" Django is detected by looking for clues of a Django project. Directories " have been traversed are cached to speed up subsequent scans. let s:seen = {} let s:django_app_modules = [ \ 'admin', \ 'apps', \ 'managers', \ 'migrations', \ 'models', \ 'templatetags', \ 'tests', \ 'urls', \ 'views', \ ] let s:django_app_dirs = [ \ 'static', \ 'templates', \ ] let s:pathsep = expand('/') let s:pathsep_p = escape(s:pathsep, '\') " Test a file name to see if it's a python module. function! s:has_module(dirname, module) return filereadable(a:dirname.'/'.a:module.'.py') \ || filereadable(a:dirname.'/'.a:module.'/__init__.py') endfunction " Test a directory for a management script> function! s:is_django_project(dirname) if filereadable(a:dirname.'/manage.py') let $_DJANGOPLUS_MANAGEMENT = a:dirname.'/manage.py' return 1 endif return 0 endfunction function! s:settings_path() abort if exists('s:django_conf_path') return s:django_conf_path endif if !exists('$_DJANGOPLUS_MANAGEMENT') || !filereadable($_DJANGOPLUS_MANAGEMENT) return '' endif for line in readfile($_DJANGOPLUS_MANAGEMENT) let module = matchstr(line, \ '\(["'']\)DJANGO_SETTINGS_MODULE\1,' \.'\s*\(["'']\)\zs\%(\2\@!.\)\+\ze\2') if !empty(module) if module =~# '\.' let module_path = join(split(module, '\.'), s:pathsep) else let module_path = module endif let module_path = fnamemodify($_DJANGOPLUS_MANAGEMENT, ':h') \.s:pathsep.module_path let conf_path = '' if filereadable(module_path.'.py') let conf_path = fnamemodify(module_path, ':h') elseif filereadable(module_path.'/__init__.py') let conf_path = module_path endif if !empty(conf_path) let s:django_conf_path = conf_path return s:django_conf_path endif endif endfor return '' endfunction function! s:is_django_settings(filename) abort let settings_path = s:settings_path() if empty(settings_path) return 0 endif return a:filename =~# '^'.settings_path.s:pathsep_p endfunction " Test a directory to see if it looks like a Django app. function! s:is_django_app(dirname) let min_matches = 2 let dirname = a:dirname if filereadable(dirname.'/__init__.py') " Apps are modules let match_count = 0 for name in s:django_app_dirs if isdirectory(dirname.'/'.name) let match_count += 1 if match_count >= min_matches return 1 endif endif endfor for name in s:django_app_modules if s:has_module(dirname, name) let match_count += 1 if match_count >= match_count return 1 endif endif endfor endif return 0 endfunction " Scan parents for a match function! s:scan(filename, func) abort if empty(a:filename) return 0 endif let dirname = fnamemodify(a:filename, ':p:h') let last_dir = '' let depth = 0 let max_depth = get(g:, 'django_max_scan_depth', 10) while depth < max_depth && dirname != last_dir && dirname !~ '^\/*$' let last_dir = dirname if has_key(s:seen, dirname) if s:seen[dirname] return 1 else let dirname = fnamemodify(dirname, ':h') continue endif endif if call(a:func, [dirname]) let s:seen[dirname] = 1 return 1 endif let s:seen[dirname] = 0 let depth += 1 let dirname = fnamemodify(dirname, ':h') endwhile return 0 endfunction " Perform a quick check to see if the the current directory is a Django " project. Returns 0 or 1 if the current directory is a Django project, and " -1 if it's not. function! s:simple_django_project(filename) let cwd = getcwd() if !has_key(s:seen, cwd) let s:seen[cwd] = s:is_django_project(cwd) endif return s:seen[cwd] ? a:filename =~# '^'.escape(cwd, '.\^$[]').s:pathsep_p : -1 endfunction " Detect Django related files function! djangoplus#detect#filetype(filename) abort if empty(a:filename) return endif let is_django = s:simple_django_project(a:filename) if is_django == -1 " Since the current directory isn't a Django project, perform a more " exhaustive scan. let is_django = s:scan(a:filename, 's:is_django_project') \ || s:scan(a:filename, 's:is_django_app') endif if is_django let b:is_django = 1 let filedir = fnamemodify(a:filename, ':h') autocmd! CursorHold call djangoplus#clear_template_cache() if a:filename =~? '\.html\?$' setfiletype htmldjango elseif s:is_django_settings(a:filename) setfiletype python let b:is_django_settings = 1 elseif a:filename =~# '\.py$' setfiletype python else for pat in get(g:, 'django_filetypes', []) if a:filename =~# glob2regpat(pat) let bft = &l:filetype if !empty(bft) let bft .= '.django' else let bft = 'django' endif execute 'setfiletype' bft endif endfor for ft in split(&l:filetype, '\.') execute 'runtime! ftplugin/'.ft.'.vim' execute 'runtime! after/ftplugin/'.ft.'.vim' endfor endif endif endfunction