├── .gitignore
├── Default.sublime-commands
├── Default.sublime-keymap
├── DjangoCommands.sublime-settings
├── Main.sublime-menu
├── README.md
├── Side Bar.sublime-menu
├── django-commands.py
├── messages.json
├── messages
├── important.md
└── install.md
└── snippets
├── ArrayField.sublime-snippet
├── BigIntegerRangeField.sublime-snippet
├── DateRangeField.sublime-snippet
├── DateTimeRangeField.sublime-snippet
├── FloatRangeField.sublime-snippet
├── HStoreField.sublime-snippet
└── IntegerRangeField.sublime-snippet
/.gitignore:
--------------------------------------------------------------------------------
1 | ###Python###
2 |
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 |
7 | # C extensions
8 | *.so
9 |
10 | # Distribution / packaging
11 | .Python
12 | env/
13 | build/
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .cache
42 | nosetests.xml
43 | coverage.xml
44 |
45 | # Translations
46 | *.mo
47 | *.pot
48 |
49 | # Django stuff:
50 | *.log
51 |
52 | # Sphinx documentation
53 | docs/_build/
54 |
55 | # PyBuilder
56 | target/
57 |
58 |
59 | ###Django###
60 |
61 | *.log
62 | *.pot
63 | *.pyc
64 | local_settings.py
65 |
66 |
67 | ###SublimeText###
68 |
69 | # cache files for sublime text
70 | *.tmlanguage.cache
71 | *.tmPreferences.cache
72 | *.stTheme.cache
73 |
74 | # workspace files are user-specific
75 | *.sublime-workspace
76 |
77 | # project files should be checked into the repository, unless a significant
78 | # proportion of contributors will probably not be using SublimeText
79 | *.sublime-project
80 |
81 | # sftp configuration file
82 | sftp-config.json
--------------------------------------------------------------------------------
/Default.sublime-commands:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "caption": "Django: New Project",
4 | "command": "django_new_project"
5 | },
6 | {
7 | "caption": "Django: New App",
8 | "command": "django_new_app"
9 | },
10 | {
11 | "caption": "Django: Run Server",
12 | "command": "django_run"
13 | },
14 | {
15 | "caption": "Django: Run Custom Server",
16 | "command": "django_run_custom"
17 | },
18 | {
19 | "caption": "Django: Migrate Database",
20 | "command": "django_migrate"
21 | },
22 | {
23 | "caption": "Django: Boilerplate",
24 | "command": "django_boiler_plate"
25 | },
26 | {
27 | "caption": "Django: Migrate App",
28 | "command": "django_migrate_app"
29 | },
30 | {
31 | "caption": "Django: Make Migration",
32 | "command": "django_make_migration"
33 | },
34 | {
35 | "caption": "Django: List Migrations",
36 | "command": "django_list_migrations"
37 | },
38 | {
39 | "caption": "Django: Set Virtual Environment",
40 | "command": "set_virtual_env"
41 | },
42 | {
43 | "caption": "Django: Terminal Here",
44 | "command": "terminal_here"
45 | },
46 | {
47 | "caption": "Django: Pip Freeze",
48 | "command": "pip_freeze"
49 | },
50 | {
51 | "caption": "Django: Pip Freeze To File",
52 | "command": "pip_freeze_to_file"
53 | },
54 | {
55 | "caption": "Django: Pip install Requirements",
56 | "command": "pip_install_requirements"
57 | },
58 | {
59 | "caption": "Django: Pip Install Packages",
60 | "command": "pip_install_packages"
61 | },
62 | {
63 | "caption": "Django: Test",
64 | "command": "django_test_app"
65 | },
66 | {
67 | "caption": "Django: Test All",
68 | "command": "django_test_all"
69 | },
70 | {
71 | "caption": "Django: Open Docs",
72 | "command": "django_open_docs"
73 | },
74 | {
75 | "caption": "Django: Search in Docs",
76 | "command": "django_search_docs"
77 | },
78 | {
79 | "caption": "Django: Set Project Interpreter",
80 | "command": "set_project_interpreter"
81 | },
82 | {
83 | "caption": "Django: Shell",
84 | "command": "django_shell"
85 | },
86 | {
87 | "caption": "Django: Help",
88 | "command": "django_help"
89 | },
90 | {
91 | "caption": "Django: Check",
92 | "command": "django_check"
93 | },
94 | {
95 | "caption": "Django: Custom Command",
96 | "command": "django_custom"
97 | },
98 | {
99 | "caption": "Django: Other Command",
100 | "command": "django_other"
101 | },
102 | {
103 | "caption": "Django: Sql Migration",
104 | "command": "django_sql_migration"
105 | },
106 | {
107 | "caption": "Django: Use Default Interpreter",
108 | "command": "change_default"
109 | },
110 | {
111 | "caption": "Django: Click",
112 | "command": "django_click"
113 | },
114 | {
115 | "caption": "Django: DB Shell",
116 | "command": "django_db_shell"
117 | }
118 | ]
119 |
--------------------------------------------------------------------------------
/Default.sublime-keymap:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "keys": ["ctrl+enter"]
4 | , "command": "django_click"
5 | , "context": [{ "key": "selector", "operator": "equal", "operand": "text.html.django" }]
6 | },
7 | {
8 | "keys": ["ctrl+alt+r"]
9 | , "command": "django_run"
10 | , "context": [{ "key": "selector", "operator": "equal", "operand": "text.html.django" }]
11 | },
12 | { "keys": ["ctrl+shift+a"]
13 | , "command": "show_overlay"
14 | , "args": {"overlay": "command_palette", "text": "Django:"} },
15 | ]
16 |
--------------------------------------------------------------------------------
/DjangoCommands.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // Path to python interpreter
3 | // It is being overriden when set_virutal_env command is invoked.
4 | "python_bin": null,
5 | // Force finding manage.py in this directory
6 | "django_project_root" : null,
7 | // List of paths where to find virtual environments
8 | "python_virtualenv_paths": [
9 | "~\\.virtualenvs", // virtualenvwrapper
10 | "~\\.venv", // venv.bash https://github.com/wuub/venv
11 | ],
12 | // Python executable version (in case of using the default)
13 | "python_version": 3,
14 | // Run server host
15 | "server_host": "127.0.0.1",
16 | // Run server in port
17 | "server_port": "8000",
18 | // Linux only: define your preferred terminal emulator
19 | "linux_terminal": "x-terminal-emulator",
20 | // Mac OSX only: define your preferred_terminal_emulator
21 | "osx_terminal": "Terminal",
22 | // Per project setting "python_interpreter" overrides "python_bin"
23 | "project_override": true,
24 | // Open browser pointint to root url after runserver command
25 | "browser_after_runserver": false,
26 | // Example Settings THIS SETTINGS ARE PER PROJECT FILE inside the settings
27 | "server_custom_command":
28 | {
29 | "command": "gunicorn",
30 | "args":
31 | [
32 | "example.wsgi:application",
33 | "--bind",
34 | "0.0.0.0:8000",
35 | "--workers=3",
36 | "--log-file=-"
37 | ]
38 | },
39 | //or
40 | "server_custom_command":
41 | {
42 | "command": "uwsgi",
43 | "args":
44 | [
45 | "--chdir=/path/to/your/project/",
46 | "--module=example.wsgi:application",
47 | "--env",
48 | "DJANGO_SETTINGS_MODULE=example.settings",
49 | "--socket=example.com:8000",
50 | "--processes=5",
51 | "--uid=1000",
52 | "--gid=2000",
53 | "--harakiri=20",
54 | "--max-requests=5000",
55 | "--vacuum"
56 | ],
57 | "run_with_python": false
58 | },
59 | //or
60 | "server_custom_command":
61 | {
62 | "command": "your_script.sh",
63 | "args":
64 | [],
65 | "run_with_python": false
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Main.sublime-menu:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "caption": "File",
4 | "id": "file",
5 | "children":
6 | [
7 | {"caption":"New Django project",
8 | "command" : "django_new_project"
9 | }
10 | ]
11 | },
12 | {
13 | "caption": "Preferences",
14 | "id": "preferences",
15 | "children":
16 | [
17 | {
18 | "caption": "Package Settings",
19 | "id": "package-settings",
20 | "children":
21 | [
22 | {
23 | "caption": "Django Manage Commands",
24 | "mnemonic": "d",
25 | "children":
26 | [
27 | {
28 | "command": "django_side_settings",
29 | "args": {"file": "${packages}/User/DjangoCommands/Default.sublime-keymap", "settings": false},
30 | "caption": "Key Bindings"
31 | },
32 | { "caption": "-" },
33 | {
34 | "command": "django_side_settings",
35 | "args": {"file": "${packages}/User/DjangoCommands.sublime-settings"},
36 | "caption": "Settings"
37 | }
38 | ]
39 | }
40 | ]
41 | }
42 | ]
43 | }
44 | ]
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ____ _ __ __
4 | | _ \(_) __ _ _ __ __ _ ___ | \/ | __ _ _ __ __ _ __ _ ___
5 | | | | | |/ _` | '_ \ / _` |/ _ \ | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \
6 | | |_| | | (_| | | | | (_| | (_) | | | | | (_| | | | | (_| | (_| | __/
7 | |____// |\__,_|_| |_|\__, |\___/ |_| |_|\__,_|_| |_|\__,_|\__, |\___|
8 | |__/ |___/ |___/
9 | ____ _
10 | / ___|___ _ __ ___ _ __ ___ __ _ _ __ __| |___
11 | | | / _ \| '_ ` _ \| '_ ` _ \ / _` | '_ \ / _` / __|
12 | | |__| (_) | | | | | | | | | | | (_| | | | | (_| \__ \
13 | \____\___/|_| |_| |_|_| |_| |_|\__,_|_| |_|\__,_|___/
14 |
15 | #########################################################################################
16 |
17 | ## Django manage commands
18 |
19 | ### The best tool for your django development.
20 |
21 | ## Overview
22 |
23 | This tool is a Sublime Text wrapper around django `manage.py` commands.
24 |
25 | ### So you can create new `Django` projects and apps directly from Sublime text like this
26 |
27 | 
28 |
29 | ### Make migrations, migrate the database or run tests
30 |
31 | 
32 |
33 | ### And run the test server
34 | 
35 |
36 | ### Even run tests
37 |
38 | 
39 |
40 |
41 | You can also run `Django: Custom Command` to access other manage.py commands. Try `Django: Help` and you will get full list of commands provided by each application.
42 |
43 | Or you can choose to use `Django: Other Command` to list and run all commands available to `manage.py`
44 |
45 | 
46 |
47 | Currently tested on Windows 7/8/10, Mac OS, Ubuntu and many other linux distros.
48 |
49 | Everything tested and running!
50 |
51 | * __Virtualenv support__
52 | * __Django boilerplate__
53 | * __Install your dependencies__
54 | * __Install new pip packages__
55 | * __Open and search in django documentation from the editor__
56 | * __Run custom servers__
57 | * __PostgreSQL specific features snippets__
58 | * __And More!__
59 |
60 | ## Installation
61 |
62 | ### Package Control
63 |
64 | The easiest way to install this is with [Package Control](http://wbond.net/sublime\_packages/package\_control).
65 |
66 | * If you just went and installed Package Control, you probably need to restart Sublime Text before doing this next bit.
67 | * Bring up the Command Palette (Command+Shift+p on OS X, Control+Shift+p on Linux/Windows).
68 | * Select "Package Control: Install Package" (it'll take a few seconds)
69 | * Select `Django Manage Commands` when the list appears.
70 |
71 | Package Control will automatically keep plugin up to date with the latest version.
72 |
73 | ## Use
74 |
75 | ### Commands
76 | Currently supports following commands:
77 |
78 | #### Django:
79 | * `Django: New Project`
80 | * `Django: New App`
81 | * `Django: Run Server`
82 | * `Django: Run Custom Server`
83 | * `Django: Boilerplate`
84 | * `Django: Test`
85 | * `Django: Test All`
86 | * `Django: Shell`
87 | * `Django: DB Shell`
88 | * `Django: Custom Command`
89 | * `Django: Other Command`
90 | * `Django: Check`
91 | * `Django: Help`
92 | * `Django: Open Docs`
93 | * `Django: Search in Docs`
94 | * `Django: Make Migration`
95 | * `Django: SQLMigration`
96 | * `Django: Migrate Database`
97 | * `Django: List Migrations`
98 | * `Django: Click`
99 |
100 | #### Virtual Environment:
101 | * `Django: Set Virtual Environment`
102 | * `Django: Terminal Here`
103 | * `Django: Pip Freeze`
104 | * `Django: Pip Freeze To File`
105 | * `Django: Pip Install Packages`
106 | * `Django: Pip Install Requirements`
107 | * `Django: Set Project Interpreter`
108 | * `Django: Use Default Interpreter`
109 |
110 | ### Settings
111 |
112 | * `python_bin`: path to python interpreter
113 | * `python_version` : default python interpreter version
114 | * `python_virtualenv_paths`: list of paths where virtualenvs are located (ex:`~/.virtualenvs/`)\*
115 | * `server_host`: host for the runserver command
116 | * `server_port`: port for the server to listen
117 | * `linux_terminal`: Linux only, used to define a custom command line emulator\*\*
118 | * `osx_terminal`: Mac OSX only, used to define a custom terminal emulator.\*\*\*
119 | * `browser_after_runserver`: set true to open a browser pointing to the root url after a run server command.
120 | * `project_override`: (Boolean) Per project setting "python_interpreter" overrides "python_bin"
121 | * `server_custom_command`: Per project setting to specify a custom server to run
122 |
123 | ***
124 |
125 | #### Each setting has it's own explanation and some examples of use at the default settings file.
126 |
127 | \*It's important to set your envs directories
128 |
129 | \*The folders in this list should be the parent folder of the virtualenv folder, not the virtualenv folder itself
130 |
131 | \*\*Default is `x-terminal-emulator` with a fallback to `xterm`
132 |
133 | \*\*\*Default is `Terminal`
134 |
135 | ### Please report any issue, bug, enhacement or comment [here](https://github.com/vladimirnani/DjangoCommands/issues)
136 | ### We'll be glad to read and work on all of them
137 |
138 |
139 |
--------------------------------------------------------------------------------
/Side Bar.sublime-menu:
--------------------------------------------------------------------------------
1 | [{ "caption": "New Django project", "id": "django-new-project", "command": "django_new_project","args": {"paths": []}}]
--------------------------------------------------------------------------------
/django-commands.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | import sublime_plugin
3 | import threading
4 | import subprocess
5 | import os
6 | import glob
7 | import re
8 |
9 | from ntpath import basename as ntbasename, split as ntsplit
10 | from shutil import which
11 | from platform import system
12 | from functools import partial
13 | from collections import OrderedDict
14 | from urllib.parse import urlencode
15 |
16 | SETTINGS_FILE = 'DjangoCommands.sublime-settings'
17 | PLATFORM = system()
18 | TERMINAL = ''
19 |
20 |
21 | def log(message):
22 | print(' - Django: {0}'.format(message))
23 |
24 |
25 | class DjangoCommand(sublime_plugin.WindowCommand):
26 | project_true = True
27 | error = False
28 | error_msg = None
29 |
30 | def __init__(self, *args, **kwargs):
31 | self.settings = sublime.load_settings(SETTINGS_FILE)
32 | self.interpreter_versions = {2: "python2",
33 | 3: "python3"} if PLATFORM is not "Windows" else {2: "python", 3: "python"}
34 | sublime_plugin.WindowCommand.__init__(self, *args, **kwargs)
35 |
36 | @property
37 | def startupinfo(self):
38 | if PLATFORM == 'Windows':
39 | startupinfo = subprocess.STARTUPINFO()
40 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
41 | return startupinfo
42 | else:
43 | return None
44 |
45 | def get_executable(self):
46 | self.project_true = self.settings.get('project_override')
47 | settings_interpreter = self.settings.get('python_bin')
48 | project = self.window.project_data()
49 | settings_exists = 'settings' in project.keys()
50 | if settings_exists and self.project_true:
51 | project_interpreter = project['settings'].get('python_interpreter')
52 | if project_interpreter is not None and self.project_true is True:
53 | return project_interpreter
54 | elif project_interpreter is not None and self.project_true is False:
55 | return settings_interpreter
56 | else:
57 | version = self.settings.get("python_version")
58 | return which(self.interpreter_versions[version])
59 | elif settings_interpreter is not None:
60 | return settings_interpreter
61 | else:
62 | version = self.settings.get("python_version")
63 | return which(self.interpreter_versions[version])
64 |
65 | def get_version(self, extb=None):
66 | if extb is None:
67 | binary = self.get_executable()
68 | else:
69 | binary = extb
70 | command = [binary, '-c', 'import django;print(django.get_version())']
71 |
72 | try:
73 | output = subprocess.check_output(command, startupinfo=self.startupinfo)
74 | except subprocess.CalledProcessError:
75 | self.error = True
76 | self.error_msg = "No django module was found, check if Django is installed in the current environment"
77 | return 0
78 | else:
79 | version = re.match(r'(\d\.\d+)', output.decode('utf-8')).group(0)
80 | return version
81 |
82 | def find_manage_py(self):
83 | django_project_root = \
84 | sublime.active_window().active_view().settings().get('django_project_root') \
85 | or self.settings.get('django_project_root')
86 | for path in [django_project_root] if django_project_root else sublime.active_window().folders():
87 | for root, dirs, files in os.walk(path):
88 | if 'manage.py' in files:
89 | return os.path.join(root, 'manage.py')
90 | self.error = True
91 | self.error_msg = "manage.py not found, unable to proceed"
92 | return None
93 |
94 | def choose(self, choices, action):
95 | on_input = partial(action, choices)
96 | self.window.show_quick_panel(choices, on_input)
97 |
98 | def go_to_project_home(self):
99 | try:
100 | if self.manage_py is None:
101 | return
102 | except:
103 | return
104 | base_dir = os.path.abspath(os.path.join(self.manage_py, os.pardir))
105 | if(os.path.exists(base_dir)):
106 | os.chdir(base_dir)
107 | else:
108 | self.error = True
109 | self.error_msg = "Project root not found"
110 | return
111 |
112 | def format_command(self, command):
113 | binary = self.get_executable()
114 | self.manage_py = self.find_manage_py()
115 | self.go_to_project_home()
116 |
117 | command = [binary, self.manage_py] + command.split(' ')
118 | return command
119 |
120 | def define_terminal(self):
121 | global TERMINAL
122 | if PLATFORM != 'Windows':
123 | settings_names = {"Linux": "linux_terminal", "Darwin": "osx_terminal"}
124 | fallbacks = {"Linux": "xterm", "Darwin": "Terminal"}
125 | TERMINAL = self.settings.get(settings_names.get(PLATFORM), fallbacks.get(PLATFORM))
126 | if not which(TERMINAL, mode=os.F_OK | os.X_OK):
127 | self.error_msg = 'terminal emulator not found: {}\nUsing fallback instead'.format(TERMINAL)
128 | self.display_error_message()
129 | TERMINAL = fallbacks.get(PLATFORM)
130 |
131 | def display_error_message(self):
132 | sublime.error_message(self.error_msg)
133 | self.error = False
134 |
135 | def display_process_error_message(self, process):
136 | outs, err = process.communicate()
137 | if err and err.decode():
138 | sublime.error_message(err.decode())
139 | else:
140 | return
141 |
142 | def run_command(self, command):
143 | self.define_terminal()
144 | commands = self.format_command(command)
145 | if self.error:
146 | self.display_error_message()
147 | return
148 | thread = CommandThread(commands)
149 | thread.start()
150 |
151 |
152 | class CommandThread(threading.Thread):
153 |
154 | def __init__(self, command, cwd='.', notsplit=False):
155 | self.command = command
156 | self.notsplit = notsplit
157 | self.cwd = cwd
158 | threading.Thread.__init__(self)
159 |
160 | def run(self):
161 | env = os.environ.copy()
162 |
163 | if PLATFORM == 'Windows':
164 | command = ['cmd.exe', '/k']
165 | command.extend(list(filter(None, self.command)))
166 | command.extend(['&&', 'timeout', '/T', '10', '&&', 'exit'])
167 |
168 | elif(self.notsplit):
169 | command = "{}".format(' '.join(self.command))
170 |
171 | else:
172 | command = "{}".format(' '.join([cmd.replace(' ', "\ ") for cmd in self.command]))
173 |
174 | if PLATFORM == 'Linux':
175 | command = [
176 | TERMINAL,
177 | '-e', 'bash -c \"{0}; read line\"'.format(command)
178 | ]
179 | if PLATFORM == 'Darwin':
180 | command = ["open", "-a", TERMINAL].extend(command)
181 |
182 | log('Command is : {0}'.format(str(command)))
183 | try:
184 | subprocess.Popen(command, env=env, cwd=self.cwd)
185 | except (subprocess.CalledProcessError, ValueError, OSError) as e:
186 | sublime.error_message("{}".format(e))
187 |
188 |
189 | class DjangoSimpleCommand(DjangoCommand):
190 | command = ''
191 | extra_args = []
192 |
193 | def get_command(self):
194 | return "{} {}".format(self.command, " ".join(self.extra_args))
195 |
196 | def run(self):
197 | self.extra_args = []
198 | command = self.get_command()
199 | self.run_command(command)
200 |
201 |
202 | class DjangoAppCommand(DjangoCommand):
203 | command = ''
204 | extra_args = []
205 | app_descriptor = 'models.py'
206 |
207 | def find_apps(self):
208 | apps = set()
209 | for project_folder in sublime.active_window().folders():
210 | dirs = [x[0] for x in os.walk(project_folder)]
211 | for dir in dirs:
212 | dir = os.path.expanduser(dir)
213 | pattern = os.path.join(dir, "*", self.app_descriptor)
214 | apps.update(list(map(lambda x: x, glob.glob(pattern))))
215 | return sorted(apps)
216 |
217 | def prettify(self, app_dir, base_dir):
218 | name = app_dir.replace(base_dir, '')
219 | name = name.replace(self.app_descriptor, '')
220 | name = name[1:-1]
221 | name = name.replace(os.path.sep, '.')
222 | return name
223 |
224 | def on_choose_app(self, apps, index):
225 | if index == -1:
226 | return
227 | name = apps[index]
228 | self.run_command(
229 | "{} {} {}".format(self.command,
230 | "".join(name),
231 | " ".join(self.extra_args)))
232 |
233 | def run(self):
234 | self.go_to_project_home()
235 | choices = self.find_apps()
236 | self.manage_py = self.find_manage_py()
237 | base_dir = os.path.dirname(self.manage_py)
238 | choices = [self.prettify(path, base_dir) for path in choices]
239 | self.choose(choices, self.on_choose_app)
240 |
241 |
242 | class DjangoOtherCommand(DjangoSimpleCommand):
243 |
244 | def get_commands(self):
245 | command = self.format_command('help --commands')
246 | out = str(subprocess.check_output(command, startupinfo=self.startupinfo))
247 | out = re.search('b\'(.*)\'', out).group(1)
248 | commands = out.split(
249 | '\\n')[:-1] if PLATFORM is not "Windows" else out.split('\\r\\n')[:-1]
250 | return commands
251 |
252 | def on_choose_command(self, commands, index):
253 | if index == -1:
254 | return
255 | name = commands[index]
256 | self.run_command(name)
257 |
258 | def run(self):
259 | commands = self.get_commands()
260 | self.choose(commands, self.on_choose_command)
261 |
262 |
263 | class DjangoRunCommand(DjangoSimpleCommand):
264 | command = 'runserver'
265 |
266 | def run(self):
267 | port = self.settings.get('server_port', "8000")
268 | host = self.settings.get('server_host', "127.0.0.1")
269 | self.extra_args = [host, port]
270 | inComannd = "{} {}:{}".format(self.command, host, port)
271 | self.run_command(inComannd)
272 | if(self.settings.get('browser_after_runserver', False)):
273 | sublime.set_timeout(
274 | lambda: self.window.run_command('open_url', {'url': 'http://{}:{}'.format(host, port)}), 100)
275 |
276 |
277 | class DjangoRunCustomCommand(DjangoSimpleCommand):
278 |
279 | def get_script(self, executable, script_name):
280 | return os.path.join(os.path.dirname(executable), script_name)
281 |
282 | def run(self):
283 | project = self.window.project_data()
284 | p_settings = 'settings' in project.keys()
285 | self.custom_command = project['settings'].get('server_custom_command') if p_settings else None
286 | self.define_terminal()
287 | executable = self.get_executable()
288 | script = self.custom_command.get('command')
289 | script = script if os.path.exists(script) else self.get_script(executable, script)
290 | commands = [executable, script, " ".join(self.custom_command.get('args'))] if self.custom_command.get(
291 | 'run_with_python', True) else ["", script, " ".join(self.custom_command.get('args'))]
292 | thread = CommandThread("{} {} {}".format(*commands), cwd=os.path.dirname(self.find_manage_py()))
293 | if self.error:
294 | self.display_error_message()
295 | return
296 | else:
297 | thread.start()
298 |
299 |
300 | class DjangoShellCommand(DjangoSimpleCommand):
301 | command = 'shell'
302 |
303 |
304 | class DjangoDbShellCommand(DjangoSimpleCommand):
305 | command = 'dbshell'
306 |
307 |
308 | class DjangoCheckCommand(DjangoSimpleCommand):
309 | command = 'check'
310 |
311 |
312 | class DjangoHelpCommand(DjangoSimpleCommand):
313 | command = 'help'
314 |
315 |
316 | class DjangoMigrateCommand(DjangoSimpleCommand):
317 | command = 'migrate'
318 |
319 |
320 | class DjangoMigrateAppCommand(DjangoAppCommand):
321 | command = 'migrate'
322 |
323 |
324 | class DjangoTestAllCommand(DjangoSimpleCommand):
325 | command = 'test'
326 |
327 |
328 | class DjangoTestAppCommand(DjangoAppCommand):
329 | command = 'test'
330 | app_descriptor = 'tests.py'
331 |
332 |
333 | class DjangoMakeMigrationCommand(DjangoSimpleCommand):
334 | command = 'makemigrations'
335 |
336 |
337 | class DjangoListMigrationsCommand(DjangoSimpleCommand):
338 | command = 'migrate'
339 | extra_args = ['--list']
340 |
341 |
342 | class DjangoSqlMigrationCommand(DjangoAppCommand):
343 | command = 'sqlmigrate'
344 |
345 | def path_leaf(self, path):
346 | head, tail = ntsplit(path)
347 | return os.path.splitext(tail)[0] or os.path.splitext(ntbasename(head))[0]
348 |
349 | def is_enabled(self):
350 | return True
351 |
352 | def on_choose_migration(self, apps, index):
353 | if index == -1:
354 | return
355 | self.extra_args.append(apps[index])
356 | self.run_command(
357 | "{} {} {}".format(self.command, self.name, " ".join(self.extra_args)))
358 |
359 | def on_app_selected(self, apps, index):
360 | self.name = apps[index]
361 | path = os.path.join(
362 | os.path.dirname(self.find_apps()[index]), 'migrations')
363 | migrations = [_path for _path in map(self.path_leaf, glob.iglob(os.path.join(path, r'*.py')))]
364 | migrations.remove('__init__')
365 | sublime.set_timeout(
366 | lambda: self.choose(migrations, self.on_choose_migration), 20)
367 |
368 | def run(self):
369 | self.extra_args = []
370 | self.go_to_project_home()
371 | choices = self.find_apps()
372 | self.manage_py = self.find_manage_py()
373 | base_dir = os.path.dirname(self.manage_py)
374 | choices = [self.prettify(path, base_dir) for path in choices]
375 | self.choose(choices, self.on_app_selected)
376 |
377 |
378 | class DjangoCustomCommand(DjangoCommand):
379 |
380 | def run(self):
381 | caption = "Django manage.py command"
382 | self.window.show_input_panel(caption, '', self.on_done, None, None)
383 |
384 | def on_done(self, command):
385 | command = command
386 | if command.strip() == '':
387 | return
388 | self.run_command(command)
389 |
390 |
391 | class VirtualEnvCommand(DjangoCommand):
392 | command = ''
393 | extra_args = []
394 |
395 | def is_enabled(self):
396 | return self.settings.get('python_bin') is not None
397 |
398 | def find_virtualenvs(self, venv_paths):
399 | binary = "Scripts" if PLATFORM == 'Windows' else "bin"
400 | venvs = set()
401 | for path in venv_paths:
402 | path = os.path.expanduser(path)
403 | pattern = os.path.join(path, "*", binary, "activate_this.py")
404 | venvs.update(list(map(os.path.dirname, glob.glob(pattern))))
405 | return sorted(venvs)
406 |
407 | def run(self):
408 | self.define_terminal()
409 | self.manage_py = self.find_manage_py()
410 | self.go_to_project_home()
411 | bin_dir = os.path.dirname(self.settings.get('python_bin'))
412 | command = [os.path.join(bin_dir, self.command)] + self.extra_args
413 | thread = CommandThread(command)
414 | thread.start()
415 |
416 |
417 | class TerminalHereCommand(VirtualEnvCommand):
418 | command = 'activate'
419 |
420 | def run(self):
421 | self.define_terminal()
422 | self.manage_py = self.find_manage_py()
423 | self.go_to_project_home()
424 | bin_dir = os.path.dirname(self.settings.get('python_bin'))
425 | if PLATFORM == 'Windows':
426 | command = ['cmd', '/k', '{}'.format(os.path.join(bin_dir, self.command))]
427 | if PLATFORM == 'Linux' or PLATFORM == 'Darwin':
428 | command = ["bash", "--rcfile", "<(echo '. ~/.bashrc && . {}')".format(os.path.join(bin_dir, self.command))]
429 | thread = CommandThread(command, notsplit=True)
430 | thread.start()
431 |
432 |
433 | class PipFreezeCommand(VirtualEnvCommand):
434 | command = 'pip'
435 | extra_args = ['freeze']
436 |
437 |
438 | class PipFreezeToFileCommand(VirtualEnvCommand):
439 | command = 'pip'
440 | extra_args = ['freeze']
441 |
442 | def on_done(self, filename):
443 | self.extra_args.append('>')
444 | self.extra_args.append(filename)
445 | VirtualEnvCommand.run(self)
446 |
447 | def run(self):
448 | self.window.show_input_panel(
449 | "File name", "requirements.txt", self.on_done, None, None)
450 |
451 |
452 | class PipInstallPackagesCommand(VirtualEnvCommand):
453 | command = 'pip'
454 | extra_args = ['install']
455 |
456 | def appendPackages(self, text):
457 | self.extra_args.append(text)
458 | super(PipInstallPackagesCommand, self).run()
459 |
460 | def run(self):
461 | self.extra_args = ['install']
462 | self.window.show_input_panel(
463 | 'Packages', '', self.appendPackages, None, None)
464 |
465 |
466 | class PipInstallRequirementsCommand(VirtualEnvCommand):
467 | command = 'pip'
468 | extra_args = ['install', '-r']
469 | file_name = 'requirements.txt'
470 |
471 | def another_file(self, text):
472 | self.extra_args.append(text)
473 | super(PipInstallRequirementsCommand, self).run()
474 |
475 | def run(self):
476 | self.extra_args = ['install', '-r']
477 | if os.path.exists(self.file_name):
478 | self.extra_args.append(self.file_name)
479 | super(PipInstallRequirementsCommand, self).run()
480 | else:
481 | sublime.message_dialog('requirements.txt not found')
482 | self.window.show_input_panel(
483 | 'File to install', '', self.another_file, None, None)
484 |
485 |
486 | class SetVirtualEnvCommand(VirtualEnvCommand):
487 |
488 | def is_enabled(self):
489 | return True
490 |
491 | def set_virtualenv(self, venvs, index):
492 | if index == -1:
493 | return
494 | name, directory = venvs[index]
495 | log('Virtual environment "{0}" is set'.format(name))
496 | binary = os.path.join(directory, 'python')
497 | self.settings.set("python_bin", binary)
498 | sublime.save_settings(SETTINGS_FILE)
499 |
500 | def run(self):
501 | venv_paths = self.settings.get("python_virtualenv_paths", [])
502 | choices = self.find_virtualenvs(venv_paths)
503 | choices = [[path.split(os.path.sep)[-2], path] for path in choices]
504 | self.choose(choices, self.set_virtualenv)
505 |
506 |
507 | class SetProjectInterpreterCommand(VirtualEnvCommand):
508 |
509 | def is_enabled(self):
510 | return True
511 |
512 | def set_project_interpreter(self, venvs, index):
513 | if index == -1:
514 | return
515 | project = self.window.project_data()
516 | if "settings" in project.keys():
517 | pass
518 | else:
519 | project["settings"] = {}
520 | project["settings"]["python_interpreter"] = os.path.join(venvs[index][1], 'python')
521 | self.window.set_project_data(project)
522 |
523 | def run(self):
524 | venv_paths = self.settings.get("python_virtualenv_paths", [])
525 | choices = self.find_virtualenvs(venv_paths)
526 | choices = [[path.split(os.path.sep)[-2], path] for path in choices]
527 | self.choose(choices, self.set_project_interpreter)
528 |
529 |
530 | class ChangeDefaultCommand(VirtualEnvCommand):
531 |
532 | def use_default(self):
533 | self.settings.erase('python_bin')
534 | sublime.save_settings(SETTINGS_FILE)
535 |
536 | def run(self):
537 | self.use_default()
538 |
539 |
540 | class DjangoClickCommand(sublime_plugin.TextCommand):
541 | TEMPLATE_DIR = 'templates'
542 |
543 | def parse_tag(self, line):
544 |
545 | RE_PARAMS = re.compile(r'(with)|(\w+=[\'"]\w+[\'"])')
546 |
547 | RE_BLOCK = re.compile(
548 | r'.*{%%\s*(?P%s)\s+(?P.+)?[\'"]?\s*%%}'
549 | % '|'.join(['include', 'extends', 'includeblocks']))
550 | RE_NAMES = re.compile(r'[\'"]([/\.\-_a-zA-Z0-9\s]+)[\'"]')
551 |
552 | line = re.sub(RE_PARAMS, "", line)
553 |
554 | match = re.match(RE_BLOCK, line)
555 |
556 | if match:
557 | targets = re.findall(RE_NAMES, match.groupdict()['names'])
558 |
559 | return match.groupdict()['tag'], targets
560 |
561 | return None, []
562 |
563 | def run(self, edit):
564 | region = self.view.sel()[0]
565 | line = self.view.line(region)
566 | line_contents = self.view.substr(line)
567 |
568 | tag, targets = self.parse_tag(line_contents)
569 |
570 | if tag:
571 | base, current_file = self.view.file_name().split(
572 | '%(separator)stemplates%(separator)s' % dict(
573 | separator=os.path.sep), 1)
574 |
575 | for one in targets:
576 | tar = os.path.join(base, self.TEMPLATE_DIR, one)
577 | if os.path.isfile(tar):
578 | window = sublime.active_window()
579 | window.open_file(tar, sublime.ENCODED_POSITION)
580 | else:
581 | for root, dirs, filenames in os.walk(base):
582 | for f in filenames:
583 | if f == one:
584 | tar = os.path.join(root, one)
585 | window = sublime.active_window()
586 | if os.path.exists(tar):
587 | window.open_file(
588 | tar, sublime.ENCODED_POSITION)
589 |
590 |
591 | class DjangoBoilerPlate(sublime_plugin.WindowCommand):
592 | options = ['urls', 'models', 'views', 'admin', 'forms', 'tests']
593 |
594 | def on_done(self, index):
595 | if index < 0:
596 | return
597 | urls = """from django.conf.urls import patterns, include, url
598 |
599 | urlpatterns = [
600 | # Examples:
601 | # url(r'^$', 'example.views.home', name='home'),
602 | # url(r'^blog/', include(blog.urls)),
603 | ]
604 | """
605 | admin = """from django.contrib import admin
606 |
607 | # Register your models here.
608 | """
609 | views = """from django.shortcuts import render
610 | # Create your views here.
611 | """
612 | models = """from django.db import models
613 | # Define your models here
614 | """
615 | forms = """from django import forms
616 | # Create your forms here
617 | """
618 | tests = """from django.test import TestCase
619 |
620 | # Create your tests here.
621 | """
622 | actions = OrderedDict()
623 | for option in self.options:
624 | actions[option] = eval(option)
625 | text = actions[self.options[index]]
626 | self.view = self.window.active_view()
627 | self.view.run_command('write_helper', {"text": text, "point": 0})
628 |
629 | def run(self):
630 | self.window.show_quick_panel(self.options, self.on_done)
631 |
632 |
633 | class WriteHelperCommand(sublime_plugin.TextCommand):
634 |
635 | def run(self, edit, point, text):
636 | self.view.insert(edit, point, text)
637 |
638 |
639 | class DjangoNewProjectCommand(SetVirtualEnvCommand):
640 |
641 | def folder_selected(self, index):
642 | self.create_project(directory=self.window.folders()[index])
643 |
644 | def check_folders(self, name):
645 | if len(self.window.folders()) == 1:
646 | self.create_project(name=name, directory=self.window.folders()[0])
647 | else:
648 | self.name = name
649 | self.window.show_quick_panel(
650 | self.window.folders(), self.folder_selected)
651 |
652 | def create_project(self, **kwargs):
653 | name = kwargs.get('name')
654 | directory = kwargs.get('directory')
655 | if name is not None:
656 | pass
657 | else:
658 | name = self.name
659 | order = os.path.join(
660 | os.path.abspath(os.path.dirname(self.interpreter)), "django-admin.py")
661 | command = [self.interpreter, order, "startproject", name, directory]
662 | log(command)
663 | process = subprocess.Popen(command, startupinfo=self.startupinfo)
664 | self.display_process_error_message(process)
665 |
666 | def set_interpreter(self, index):
667 | if index == -1:
668 | return
669 | name, self.interpreter = self.choices[index]
670 | if name is not "default":
671 | self.interpreter = os.path.join(self.interpreter, 'python')
672 | if self.get_version(self.interpreter) == 0:
673 | self.error_msg = "No module 'django' found in the selected environment"
674 | self.display_error_message()
675 | return
676 | self.window.show_input_panel(
677 | "Project name", "", self.check_folders, None, None)
678 |
679 | def run(self):
680 | venv_paths = self.settings.get("python_virtualenv_paths", [])
681 | version = self.settings.get("python_version")
682 | envs = self.find_virtualenvs(venv_paths)
683 | self.choices = [[path.split(os.path.sep)[-2], path] for path in envs]
684 | self.choices.append(
685 | ["default", which(self.interpreter_versions[version])])
686 | sublime.message_dialog(
687 | "Select a python interpreter for the new project")
688 | self.window.show_quick_panel(self.choices, self.set_interpreter)
689 |
690 |
691 | class DjangoNewAppCommand(DjangoSimpleCommand):
692 | command = 'startapp'
693 |
694 | def create_app(self, text):
695 | self.extra_args.append(text)
696 | command = self.format_command(self.get_command())
697 | log(command)
698 | if self.error:
699 | self.display_error_message()
700 | else:
701 | process = subprocess.Popen(command, env=os.environ.copy(), stderr=subprocess.PIPE,
702 | stdout=subprocess.PIPE, startupinfo=self.startupinfo)
703 | self.display_process_error_message(process)
704 |
705 | def run(self):
706 | if self.get_version() == 0:
707 | self.display_error_message()
708 | return
709 | self.extra_args = list()
710 | self.window.show_input_panel(
711 | "App name", '', self.create_app, None, None)
712 |
713 |
714 | class DjangoOpenDocsCommand(DjangoCommand):
715 |
716 | def run(self):
717 | version = self.get_version()
718 | if version == 0:
719 | self.display_error_message()
720 | return
721 | url = "https://docs.djangoproject.com/en/{}/".format(version)
722 | self.window.run_command('open_url', {'url': url})
723 |
724 |
725 | class DjangoSearchDocsCommand(DjangoCommand):
726 |
727 | def on_done(self, text):
728 | release = self.get_version()
729 | if release == 0:
730 | self.display_error_message()
731 | return
732 | params = {'q': text}
733 | url = "https://docs.djangoproject.com/en/{}/search/?{}".format(
734 | release,
735 | urlencode(params))
736 | self.window.run_command('open_url', {'url': url})
737 |
738 | def run(self):
739 | sel = self.window.active_view().substr(self.window.active_view().sel()[0])
740 | if(sel is not None):
741 | selection = sel
742 | else:
743 | selection = ''
744 | self.window.show_input_panel('Search:', selection, self.on_done, None, None)
745 |
746 |
747 | class DjangoSideSettingsCommand(sublime_plugin.WindowCommand):
748 |
749 | def run(self, file, settings=True):
750 | self.window.run_command('new_window')
751 | window = sublime.active_window()
752 | window.run_command('open_file', {'file': SETTINGS_FILE if settings else 'Default.sublime-keymap'})
753 | window.active_view().set_read_only(True)
754 | window.run_command('set_layout', {
755 | "cols": [0.0, 0.5, 1.0],
756 | "rows": [0.0, 1.0],
757 | "cells": [[0, 0, 1, 1], [1, 0, 2, 1]]
758 | })
759 | window.run_command('open_file', {'file': file})
760 |
--------------------------------------------------------------------------------
/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "install": "messages/install.md",
3 | "1.7.9": "messages/important.md"
4 | }
--------------------------------------------------------------------------------
/messages/important.md:
--------------------------------------------------------------------------------
1 | Django manage commands 1.7.9
2 |
3 | - Fallback for 'linux-terminal' setting with a dash is dropped, now is essential to use 'linux_terminal' setting with and underscore.
4 |
5 | - Linux extended compatibility dropping 'gnome-terminal' in favor of 'x-terminal-emulator' as the default 'linux_terminal' setting and with 'xterm' as a fallback.
6 |
7 | - Easier access to user settings and keybindings, now showing both default and user defined files side by side to ease the definition of user settings.
8 |
9 | - Mac OSX users now can select their preferred terminal emulator to be triggered to run the corresponding command. Use `osx_terminal` setting.
10 |
11 | - Windows users, would you like to be able to select another terminal instead of cmd.exe like mintty, cmder or git-bash? If so please open an Issue(only one please so others can comment on it, and keep the issue tracker organized) at our github repo and let us know.
12 |
13 | - Windows slight performance optimization.
14 |
15 | - Minor fixes.
--------------------------------------------------------------------------------
/messages/install.md:
--------------------------------------------------------------------------------
1 | ____ _ __ __
2 | | _ \(_) __ _ _ __ __ _ ___ | \/ | __ _ _ __ __ _ __ _ ___
3 | | | | | |/ _` | '_ \ / _` |/ _ \ | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \
4 | | |_| | | (_| | | | | (_| | (_) | | | | | (_| | | | | (_| | (_| | __/
5 | |____// |\__,_|_| |_|\__, |\___/ |_| |_|\__,_|_| |_|\__,_|\__, |\___|
6 | |__/ |___/ |___/
7 | ____ _
8 | / ___|___ _ __ ___ _ __ ___ __ _ _ __ __| |___
9 | | | / _ \| '_ ` _ \| '_ ` _ \ / _` | '_ \ / _` / __|
10 | | |__| (_) | | | | | | | | | | | (_| | | | | (_| \__ \
11 | \____\___/|_| |_| |_|_| |_| |_|\__,_|_| |_|\__,_|___/
12 |
13 | #########################################################################################
14 |
15 |
16 | - Ctrl + Shift + A: opens a menu with all Django commands.
17 |
18 | - Remember to set the path to the directory where your virtual environments are installed in "python_virtualenv_paths" for the plugin to work correclty, as many directories as you need can be added.
19 |
20 | - Enjoy and please let us know if you run into any issue.
21 |
22 | :smile:
--------------------------------------------------------------------------------
/snippets/ArrayField.sublime-snippet:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | psarray
5 |
6 | source.python
7 | ArrayField
8 |
9 |
--------------------------------------------------------------------------------
/snippets/BigIntegerRangeField.sublime-snippet:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | psbigintrange
5 |
6 | source.python
7 | BigIntegerRangeField
8 |
9 |
--------------------------------------------------------------------------------
/snippets/DateRangeField.sublime-snippet:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | psdaterange
5 |
6 | source.python
7 | DateRangeField
8 |
9 |
--------------------------------------------------------------------------------
/snippets/DateTimeRangeField.sublime-snippet:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | psdatimerange
5 |
6 | source.python
7 | DateTimeRangeField
8 |
9 |
--------------------------------------------------------------------------------
/snippets/FloatRangeField.sublime-snippet:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | psflrange
5 |
6 | source.python
7 | FloatRangeField
8 |
9 |
--------------------------------------------------------------------------------
/snippets/HStoreField.sublime-snippet:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | pshstore
5 |
6 | source.python
7 | HStoreField
8 |
9 |
--------------------------------------------------------------------------------
/snippets/IntegerRangeField.sublime-snippet:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | psintrange
5 |
6 | source.python
7 | IntegerRangeField
8 |
9 |
--------------------------------------------------------------------------------