Permalink
Browse files

Gist editing + various other improvements.

Refactored lots of code so that it doesn't use global variables.

Added a much better gist editing workflow:
  - If a gist is created from the whole buffer, buffer is marked as a
    gist buffer.
  - Pressing enter in the gist list doesn't copy the last file to the
    clipboard. Instead, every file from that gist is opened as a gist
    buffer.
  - Gist buffers have "Gist" in their modeline and have additional
    commands available: copy gist URL, open gist in browser and update
    gist (which updates the corresponding file in the gist with contents
    of the gist buffer).

Open in browser preference was removed as it's now available in the
menu.
  • Loading branch information...
1 parent df333ec commit 577cad50f288fe7d3dbcdc4fb66efb5715cb9caf @technocoreai technocoreai committed Jan 12, 2012
Showing with 129 additions and 83 deletions.
  1. +1 −0 Default (Linux).sublime-keymap
  2. +1 −0 Default (OSX).sublime-keymap
  3. +1 −0 Default (Windows).sublime-keymap
  4. +12 −0 Gist.sublime-commands
  5. +1 −4 Gist.sublime-settings
  6. +3 −0 Main.sublime-menu
  7. +110 −79 gist.py
View
1 Default (Linux).sublime-keymap
@@ -1,5 +1,6 @@
[
{ "keys": ["ctrl+k", "ctrl+i"], "command": "gist" },
{ "keys": ["ctrl+k", "ctrl+l"], "command": "gist_private" },
+ { "keys": ["ctrl+k", "ctrl+s"], "command": "gist_update" },
{ "keys": ["ctrl+shift+g"], "command": "gist_list" }
]
View
1 Default (OSX).sublime-keymap
@@ -1,5 +1,6 @@
[
{ "keys": ["super+k", "super+i"], "command": "gist" },
{ "keys": ["super+k", "super+l"], "command": "gist_private" },
+ { "keys": ["super+k", "super+s"], "command": "gist_update" },
{ "keys": ["ctrl+super+g"], "command": "gist_list" }
]
View
1 Default (Windows).sublime-keymap
@@ -1,5 +1,6 @@
[
{ "keys": ["ctrl+k", "ctrl+i"], "command": "gist" },
{ "keys": ["ctrl+k", "ctrl+l"], "command": "gist_private" },
+ { "keys": ["ctrl+k", "ctrl+s"], "command": "gist_update" },
{ "keys": ["ctrl+shift+g"], "command": "gist_list" }
]
View
12 Gist.sublime-commands
@@ -8,6 +8,18 @@
"command": "gist_private"
},
{
+ "caption": "Gist: Copy Gist URL",
+ "command": "gist_copy_url"
+ },
+ {
+ "caption": "Gist: Open Gist In Browser",
+ "command": "gist_open_browser"
+ },
+ {
+ "caption": "Gist: Update Gist",
+ "command": "gist_update"
+ },
+ {
"caption": "Gist: Get List",
"command": "gist_list"
}
View
5 Gist.sublime-settings
@@ -7,8 +7,5 @@
// Proxy server
// Format: "http://user:pass@proxy:port"
- "https_proxy": "",
-
- // Open created gists in the browser
- "open_in_browser": false
+ "https_proxy": ""
}
View
3 Main.sublime-menu
@@ -11,6 +11,9 @@
[
{ "command": "gist", "caption": "Create Public Gist" },
{ "command": "gist_private", "caption": "Create Private Gist" },
+ { "command": "gist_copy_url", "caption": "Copy Gist URL" },
+ { "command": "gist_open_browser", "caption": "Open Gist In Browser"},
+ { "command": "gist_update", "caption": "Update Gist" },
{ "command": "gist_list", "caption": "Get Gist List" }
]
}
View
189 gist.py
@@ -11,11 +11,8 @@
DEFAULT_CREATE_PUBLIC_VALUE = 'false'
DEFAULT_USE_PROXY_VALUE = 'false'
-_selectedText = ''
-_fileName = ''
-_gistsUrls = []
settings = sublime.load_settings('Gist.sublime-settings')
-url = 'https://api.github.com/gists'
+GISTS_URL = 'https://api.github.com/gists'
class GistMissingCredentialsException(Exception):
pass
@@ -112,39 +109,51 @@ def _fn(*args, **kwargs):
sublime.error_message("GitHub username or password isn't provided in Gist.sublime-settings file")
return _fn
-def create_gist(description, public):
- data = json.dumps({ 'description': description, 'public': public, 'files': { _fileName: {'content': _selectedText} }})
- result = api_request(url, data)
- sublime.set_clipboard(result['html_url'])
- if settings.get("open_in_browser"):
- webbrowser.open(result['html_url'])
- sublime.status_message("Gist: " + result['html_url'])
-
+@catching_credential_errors
+def create_gist(public, view, text, filename, description):
+ data = json.dumps({'description': description, 'public': public, 'files': {filename: {'content': text}}})
+ gist = api_request(GISTS_URL, data)
+ gist_html_url = gist['html_url']
+ sublime.set_clipboard(gist_html_url)
+ sublime.status_message("Gist: " + gist_html_url)
+ if view:
+ gistify_view(view, gist, filename)
+
+@catching_credential_errors
+def update_gist(gist_url, gist_filename, text):
+ data = json.dumps({'files': {gist_filename: {'content': text}}})
+ result = api_request(gist_url, data, method="PATCH")
+ sublime.status_message("Gist updated")
+
+def gistify_view(view, gist, gist_filename):
+ if not view.name():
+ view.set_name(gist_filename)
+
+ view.settings().set('gist_html_url', gist["html_url"])
+ view.settings().set('gist_url', gist["url"])
+ view.settings().set('gist_filename', gist_filename)
+ view.set_status("Gist", "Gist")
+
+@catching_credential_errors
def get_gist(url_gist):
- gists = api_request(url_gist)
- for gist in gists['files']:
- sublime.set_clipboard(gists['files'][gist]['content'])
-
-def get_gists():
- gists = api_request(url)
-
- gistsNames = []
+ gist = api_request(url_gist)
+ gist_title = gist.get('description') or u'[No name]'
+ for gist_filename, file_data in gist['files'].items():
+ view = sublime.active_window().new_file()
- for gist in gists:
- if gist['description']:
- gistsNames.append(gist['description'])
- else:
- gistsNames.append(u'[No Name]')
-
- _gistsUrls.append(gist['url'])
+ gistify_view(view, gist, gist_filename)
- return gistsNames
+ edit = view.begin_edit()
+ view.insert(edit, 0, file_data['content'])
+ view.end_edit(edit)
-def api_request(url_api, data = ''):
- if not 'ssl' in sys.modules and not os.name == 'nt':
- return api_request_wget(url_api, data)
+def get_gists():
+ return api_request(GISTS_URL)
+def api_request_native(url_api, data = '', method = None):
request = urllib2.Request(url_api)
+ if method:
+ request.get_method = lambda: method
request.add_header('Authorization', 'Basic ' + base64.urlsafe_b64encode("%s:%s" % get_credentials()))
request.add_header('Accept', 'application/json')
request.add_header('Content-Type', 'application/json')
@@ -162,7 +171,7 @@ def api_request(url_api, data = ''):
return json.loads(response.read())
-def api_request_wget(url_api, data = ''):
+def api_request_wget(url_api, data = '', method = None):
dirs = ['/usr/local/sbin', '/usr/local/bin', '/usr/sbin', '/usr/bin', '/sbin', '/bin']
for dir in dirs:
@@ -197,71 +206,93 @@ def api_request_wget(url_api, data = ''):
returncode = process.wait()
if returncode != 0:
- error = BaseException('Wget exits with code %s' % returncode)
+ error = Exception('Wget exits with code %s' % returncode)
raise error
return json.loads(response)
-class PromptPublicGistCommand(sublime_plugin.WindowCommand):
- @catching_credential_errors
- def run(self):
- get_credentials()
- fileName = os.path.basename(self.window.active_view().file_name()) if self.window.active_view().file_name() else ''
- self.window.show_input_panel('Public Gist File Name: (optional):', fileName, self.on_done_input_file_name, None, None)
+if not 'ssl' in sys.modules and not os.name == 'nt':
+ api_request = api_request_wget
+else:
+ api_request = api_request_native
- def on_done_input_file_name(self, fileName):
- global _fileName
- _fileName = fileName
- self.window.show_input_panel('Public Gist Description (optional):', '', self.on_done_input_description, None, None)
+class GistCommand(sublime_plugin.TextCommand):
+ public = True
- @catching_credential_errors
- def on_done_input_description(self, description):
- create_gist(description, "true")
+ def mode(self):
+ return "Public" if self.public else "Private"
-class PromptPrivateGistCommand(sublime_plugin.WindowCommand):
@catching_credential_errors
- def run(self):
+ def run(self, edit):
get_credentials()
- fileName = os.path.basename(self.window.active_view().file_name()) if self.window.active_view().file_name() else ''
- self.window.show_input_panel('Private Gist File Name: (optional):', fileName, self.on_done_input_file_name, None, None)
+ selections = [region for region in self.view.sel() if not region.empty()]
- def on_done_input_file_name(self, fileName):
- global _fileName
- _fileName = fileName
- self.window.show_input_panel('Private Gist Description (optional):', '', self.on_done_input_description, None, None)
+ if len(selections) == 0:
+ selections = [sublime.Region(0, self.view.size())]
+ gistify = True
+ else:
+ gistify = False
+
+ for region in selections:
+ self.prompt_gist_name(gistify, self.view.substr(region))
+
+ def prompt_gist_name(self, gistify, text):
+ filename = os.path.basename(self.view.file_name()) if self.view.file_name() else ''
+ self.view.window().show_input_panel(
+ '%s Gist File Name: (optional):' % self.mode(), filename,
+ lambda filename:
+ self.view.window().show_input_panel(
+ '%s Gist Description (optional):' % self.mode(), '',
+ lambda description:
+ create_gist(self.public, self.view if gistify else None, text, filename, description),
+ None, None),
+ None, None)
+
+class GistCopyUrl(sublime_plugin.TextCommand):
+ def is_enabled(self):
+ return self.view.settings().get("gist_html_url") is not None
- @catching_credential_errors
- def on_done_input_description(self, description):
- create_gist(description, "false")
+ def run(self, edit):
+ sublime.set_clipboard(self.view.settings().get("gist_html_url"))
+
+class GistOpenBrowser(sublime_plugin.TextCommand):
+ def is_enabled(self):
+ return self.view.settings().get("gist_html_url") is not None
-class GistCommand(sublime_plugin.TextCommand):
def run(self, edit):
- for selectedRegion in self.view.sel():
- if not selectedRegion.empty():
- global _selectedText
- _selectedText = self.view.substr(selectedRegion)
- self.view.window().run_command('prompt_public_gist')
- else:
- _selectedText = self.view.substr(sublime.Region(0, self.view.size()))
- self.view.window().run_command('prompt_public_gist')
+ webbrowser.open(self.view.settings().get("gist_html_url"))
+
+class GistUpdateCommand(sublime_plugin.TextCommand):
+ def is_enabled(self):
+ return self.view.settings().get("gist_url") is not None
+
+ def is_visible(self):
+ # wget doesn't support changing HTTP method
+ return api_request != api_request_wget
-class GistPrivateCommand(sublime_plugin.TextCommand):
+ @catching_credential_errors
def run(self, edit):
- for selectedRegion in self.view.sel():
- if not selectedRegion.empty():
- global _selectedText
- _selectedText = self.view.substr(selectedRegion)
- self.view.window().run_command('prompt_private_gist')
- else:
- _selectedText = self.view.substr(sublime.Region(0, self.view.size()))
- self.view.window().run_command('prompt_private_gist')
+ text = self.view.substr(sublime.Region(0, self.view.size()))
+ update_gist(self.view.settings().get("gist_url"), self.view.settings().get("gist_filename"), text)
+
+class GistPrivateCommand(GistCommand):
+ public = False
class GistListCommand(sublime_plugin.WindowCommand):
@catching_credential_errors
def run(self):
gists = get_gists()
- self.window.show_quick_panel(gists, self.on_done)
- @catching_credential_errors
- def on_done(self, num):
- get_gist(_gistsUrls[num])
+ gist_urls = []
+ gist_names = []
+
+ for gist in gists:
+ if gist['description']:
+ gist_names.append(gist['description'])
+ else:
+ gist_names.append(u'[No Name]')
+ gist_urls.append(gist['url'])
+
+ self.window.show_quick_panel(
+ gist_names,
+ lambda num: get_gist(gist_urls[num]))

0 comments on commit 577cad5

Please sign in to comment.