local plen_status_ok, _ = pcall(require, "plenary") if not plen_status_ok then return end local term_stat_ok, _ = pcall(require, "toggleterm.terminal") if not term_stat_ok then return end local inp = require "django.input" local helpers = require "django.helpers" local toggleterm = require "toggleterm" local terms = require "toggleterm.terminal" local CHARS = "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)" local function generate_secret_key() local chars = {} for x in CHARS:gmatch "[a-zA-Z0-9!@#$%^&*(-_=+)]" do table.insert(chars, x) end local key = "" math.randomseed(os.time()) for _ = 1, 50 do key = key .. chars[math.random(1, #chars)] end return key end local M = {} local Path = require "plenary.path" local env_opts = { secret_key = generate_secret_key(), allowed_hosts = { "localhost", "10.0.2.2", "127.0.0.1" }, local_ip = "", debug = "True", database = { user = "postgres", password = "postgres", dbname = "db", port = "5433", address = "127.0.0.1", }, admin = { username = "admin", email = "adm@email.com", password = "", }, email = { host = "", port = "587", host_user = "", host_password = "", use_tls = "True", default_from_email = "", }, celery = { result_backend = "django-db", broker_url = "redis://localhost:6379", accept_content = "application/json", result_serializer = "json", task_serializer = "json", timezone = "America/Sao_Paulo", task_time_limit = "30 * 60", }, } M.title = "Django.nvim" local function execute_command(cmd, args) local ok, err = pcall(cmd, args) ---@diagnostic disable-next-line: param-type-mismatch if not ok then pcall(vim.notify, err, vim.log.levels.ERROR) end end local function setup_opts(opts) vim.validate { opts = { opts, "table", true } } opts = vim.tbl_deep_extend("force", env_opts, opts or {}) vim.validate { secret_key = { opts.secret_key, "string" }, allowed_hosts = { opts.allowed_hosts, "table" }, database = { opts.database, "table" }, admin = { opts.admin, "table" }, email = { opts.email, "table" }, celery = { opts.celery, "table" }, } return opts end local function file_exists(name) local f = io.open(name, "r") if f ~= nil then io.close(f) return true else return false end end local function create_form_file(dir) local file = io.open(helpers.add_trailing_slash(dir) .. "forms.py", "w") if file ~= nil then file:write("from django import forms") io.close(file) end end local function create_template_static_dirs(name, dir) execute_command(os.execute, "mkdir -p " .. dir .. "/static/" .. name .. "/css") execute_command(os.execute, "mkdir -p " .. dir .. "/static/" .. name .. "/img") execute_command(os.execute, "mkdir -p " .. dir .. "/static/" .. name .. "/js") execute_command(os.execute, "mkdir -p " .. dir .. "/templates/" .. name) end local function get_app_name(path) local name = helpers.split(helpers.add_trailing_slash(path)) return name[#name] end local function check_app(path) return vim.loop.fs_stat(helpers.add_trailing_slash(path) .. "apps.py") ~= nil end local function get_module_name(path) return path:gsub(Path.path.sep, ".") end local function perform_create_app(value) local appname = get_app_name(value) if appname then if vim.loop.fs_stat(value) == nil then execute_command(os.execute, "mkdir " .. value) end if check_app(value) == true then vim.notify("This app already exists", vim.log.levels.ERROR, { title = M.title }) return end execute_command(os.execute, "./manage.py startapp " .. appname .. " " .. value) if check_app(value) == true then create_form_file(value) create_template_static_dirs(value, value) execute_command( os.execute, "echo -e \"from django.urls import path\n\napp_name = '" .. appname .. "'\n\nurlpatterns = []\" > " .. value .. "/urls.py" ) execute_command( os.execute, 'echo -e " internal_app = True" >> ' .. helpers.add_trailing_slash(value) .. "apps.py" ) local cmd = string.format( 'sed -i "s/"%s"/"%s"/" %s', appname, get_module_name(value), helpers.add_trailing_slash(value) .. "apps.py" ) os.execute(cmd) end vim.notify("App " .. value .. " created!", vim.log.levels.INFO, { title = M.title .. " - startapp" }) end end local function perform_create_package(value) if vim.loop.fs_stat(value) == nil then execute_command(os.execute, "mkdir -p " .. value) execute_command(os.execute, "touch " .. helpers.add_trailing_slash(value) .. "__init__.py") vim.notify("Package " .. value .. " created!", vim.log.levels.INFO, { title = M.title .. " - create package" }) end end local function env_ip(ip) if #ip > 0 then return ", " .. ip end return ip end function M.create_app() inp.open({ prompt = "create app: " }, perform_create_app) end function M.create_package() inp.open({ prompt = "create package: " }, perform_create_package) end function M.create_env_file(opts) local opts = setup_opts(opts) if file_exists ".env" then vim.notify("File .env already exists", vim.log.levels.WARN, { title = "Create env file" }) return end local env_file = io.open(".env", "w") local env_text = [[ SECRET_KEY=']] .. opts.secret_key .. "'\n" .. "ALLOWED_HOSTS=localhost, 10.0.2.2, 127.0.0.1" .. env_ip(opts.local_ip) .. "\n" .. "DEBUG=" .. opts.debug .. "\n\n" .. "DATABASE_URL=postgres://" .. opts.database.user .. ":" .. opts.database.password .. "@" .. opts.database.address .. ":" .. opts.database.port .. "/" .. opts.database.dbname .. "\n\n" .. "DB_USER=\n" .. "DB_PASSWORD=\n" .. "DB_HOST=\n" .. "DB_PORT=\n" .. "\n" .. "ADMIN_USERNAME=" .. opts.admin.username .. "\n" .. "ADMIN_EMAIL=" .. opts.admin.email .. "\n" .. "ADMIN_PASSWORD=" .. opts.admin.password .. "\n\n" .. "EMAIL_HOST=" .. opts.email.host .. "\n" .. "EMAIL_PORT=" .. opts.email.port .. "\n" .. "EMAIL_HOST_USER=" .. opts.email.host_user .. "\n" .. "EMAIL_HOST_PASSWORD=" .. opts.email.host_password .. "\n" .. "EMAIL_USE_TLS=" .. opts.email.use_tls .. "\n" .. "DEFAULT_FROM_EMAIL=" .. opts.email.default_from_email .. "\n\n" .. "CELERY_RESULT_BACKEND=" .. opts.celery.result_backend .. "\n" .. "CELERY_BROKER_URL=" .. opts.celery.broker_url .. "\n" .. "CELERY_ACCEPT_CONTENT=" .. opts.celery.accept_content .. "\n" .. "CELERY_RESULT_SERIALIZER=" .. opts.celery.result_serializer .. "\n" .. "CELERY_TASK_SERIALIZER=" .. opts.celery.task_serializer .. "\n" .. "CELERY_TIMEZONE=" .. opts.celery.timezone .. "\n" .. "CELERY_TASK_TIME_LIMIT=" .. opts.celery.task_time_limit .. "\n\n" .. "AWS_ACCESS_KEY_ID=\n" .. "AWS_SECRET_ACCESS_KEY=\n" .. "AWS_STORAGE_BUCKET_NAME=\n" .. "AWS_S3_ENDPOINT_URL=\n" .. "AWS_LOCATION=\n" if env_file ~= nil then env_file:write(env_text) env_file:close() end end function M.manage_run_server(custom_command) local term_num = 2 local term = terms.get(term_num, true) if not file_exists "Makefile" then if not file_exists "makefile" then custom_command = "./manage.py runserver 0.0.0.0:8000" end end if term then term:toggle() else toggleterm.exec(custom_command, term_num, 100, ".", "float", "runserver") end end function M.manage_shell_plus(is_plus) local term_num = 10 local term = terms.get(term_num, true) local cmd = "./manage.py shell" if is_plus then cmd = "./manage.py shell_plus" end if term then term:toggle() else toggleterm.exec(cmd, term_num, 100, ".", "float", "shell_plus", true) end end function M.manage_make_migrations() local term_num = 3 toggleterm.exec("./manage.py makemigrations", term_num, 100, ".", "float", "make_migrations", false) end function M.manage_migrate() local term_num = 4 toggleterm.exec("./manage.py migrate", term_num, 100, ".", "float", "migrate", false) end function M.check() local term_num = 5 toggleterm.exec("./manage.py check", term_num, 100, ".", "float", "check", false) end function M.show_migrations() local term_num = 6 toggleterm.exec("./manage.py showmigrations", term_num, 100, ".", "float", "showmigrations", false) end function M.run_celery() local term_num = 7 local term = terms.get(term_num, true) if term then term:toggle() else toggleterm.exec("make run_celery", term_num, 100, ".", "float", "run_celery", false) end end return M