Created
August 7, 2012 06:31
-
-
Save tav/3282403 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """Tav's Sublime Kit.""" | |
| import re | |
| import sublime, sublime_plugin | |
| from datetime import datetime | |
| from json import dump, load | |
| from os.path import dirname, expanduser, isdir, isfile, realpath, split | |
| from time import time | |
| # ----------------------------------------------------------------------------- | |
| # Region Skipping | |
| # ----------------------------------------------------------------------------- | |
| linebreaks_re = re.compile('\n[\t ]*\n+') | |
| find_linebreaks = linebreaks_re.search | |
| split_linebreaks = linebreaks_re.split | |
| def skip_region(view, scroll): | |
| size = view.size() | |
| start = view.sel()[0].begin() | |
| if scroll == 1: | |
| content = view.substr(sublime.Region(start, size)) | |
| segment = content.lstrip() | |
| diff = len(content) - len(segment) | |
| match = find_linebreaks(segment) | |
| if match: | |
| idx = start + diff + match.end() - 1 | |
| else: | |
| idx = size | |
| else: | |
| content = view.substr(sublime.Region(0, start)) | |
| segment = content.rstrip() | |
| diff = len(content) - len(segment) | |
| split = split_linebreaks(segment) | |
| if split: | |
| idx = start - diff - len(split[-1]) - 1 | |
| else: | |
| idx = 0 | |
| row, _ = view.rowcol(idx) | |
| pt = view.text_point(row, 0) | |
| view.sel().clear() | |
| view.sel().add(sublime.Region(pt)) | |
| view.show(pt) | |
| class SkipRegionDownCommand(sublime_plugin.TextCommand): | |
| def run(self, edit): | |
| skip_region(self.view, 1) | |
| class SkipRegionUpCommand(sublime_plugin.TextCommand): | |
| def run(self, edit): | |
| skip_region(self.view, -1) | |
| # ----------------------------------------------------------------------------- | |
| # Pager | |
| # ----------------------------------------------------------------------------- | |
| def page(view, scroll): | |
| end, _ = view.rowcol(view.size()) | |
| row, col = view.rowcol(view.sel()[0].begin()) | |
| row += scroll | |
| if not (0 <= row <= end): | |
| return | |
| pt = view.text_point(row, 0) | |
| view.sel().clear() | |
| view.sel().add(sublime.Region(pt)) | |
| view.show_at_center(pt) | |
| class PagerDownCommand(sublime_plugin.TextCommand): | |
| def run(self, edit): | |
| page(self.view, 1) | |
| class PagerUpCommand(sublime_plugin.TextCommand): | |
| def run(self, edit): | |
| page(self.view, -1) | |
| # ----------------------------------------------------------------------------- | |
| # Angilify | |
| # ----------------------------------------------------------------------------- | |
| class AngilifyCommand(sublime_plugin.TextCommand): | |
| def run(self, edit): | |
| view = self.view | |
| for region in view.sel(): | |
| if region.empty(): | |
| region = view.line(region) | |
| view.insert(edit, region.begin(), '<') | |
| view.insert(edit, region.end()+1, '>') | |
| # ----------------------------------------------------------------------------- | |
| # Column Repeater | |
| # ----------------------------------------------------------------------------- | |
| class RepeatColumnCommand(sublime_plugin.TextCommand): | |
| def run(self, edit): | |
| view = self.view | |
| for region in view.sel(): | |
| idx = region.begin() - 1 | |
| if idx < 0: | |
| continue | |
| char = view.substr(idx) | |
| if char in ('\n', '\t'): | |
| continue | |
| _, col = view.rowcol(idx) | |
| view.insert(edit, idx, char * (78 - col)) | |
| # ----------------------------------------------------------------------------- | |
| # Utility Cache | |
| # ----------------------------------------------------------------------------- | |
| class RecentSet(dict): | |
| __slots__ = ('_clock',) | |
| def __init__(self, *args): | |
| self._clock = 0 | |
| for arg in args: | |
| self.add(arg) | |
| def add(self, key): | |
| dict.__setitem__(self, key, self._clock) | |
| self._clock += 1 | |
| def elems(self): | |
| return sorted(self.keys(), key=lambda x: self[x], reverse=1)[:100] | |
| # ----------------------------------------------------------------------------- | |
| # File Status | |
| # ----------------------------------------------------------------------------- | |
| HISTORY_FILE = expanduser("~/.sublime.history") | |
| if 'FILE_CACHE' not in globals(): | |
| args = () | |
| if isfile(HISTORY_FILE): | |
| try: | |
| history = open(HISTORY_FILE, 'rb') | |
| args = load(history) | |
| history.close() | |
| except Exception, err: | |
| print "ERROR: couldn't open history: %s", err | |
| FILE_CACHE = RecentSet(*args) | |
| class FileModifiedStatusEventHandler(sublime_plugin.EventListener): | |
| last_saved = 0 | |
| def save_file_usage(self, view): | |
| filename = view.file_name() | |
| if not filename: | |
| return | |
| FILE_CACHE.add(filename) | |
| now = time() | |
| if (now - self.last_saved) < 10: | |
| return | |
| files = FILE_CACHE.elems() | |
| if not files: | |
| return | |
| try: | |
| history = open(HISTORY_FILE, "wb") | |
| dump(files, history) | |
| history.close() | |
| self.last_saved = now | |
| except Exception, err: | |
| print "ERROR: couldn't save history: %s" % err | |
| def on_close(self, view): | |
| self.save_file_usage(view) | |
| def on_load(self, view): | |
| self.save_file_usage(view) | |
| view.set_status("-", "-:--") | |
| def on_modified(self, view): | |
| view.set_status("-", "-:**") | |
| def on_new(self, view): | |
| view.set_status("-", "-:??") | |
| def on_post_save(self, view): | |
| self.save_file_usage(view) | |
| view.set_status("-", "-:--") | |
| class GetRecentCommand(sublime_plugin.WindowCommand): | |
| showing = 0 | |
| def run(self): | |
| if self.showing: | |
| pass | |
| # print "hiding" | |
| # self.showing = 0 | |
| # self.window.run_command("hide_quick_panel", {"cancel": True}) | |
| else: | |
| print "showing" | |
| self.showing = FILE_CACHE.elems() | |
| self.window.show_quick_panel(self.showing, self.select) | |
| def select(self, idx): | |
| showing = self.showing | |
| self.showing = 0 | |
| if idx == -1: | |
| return | |
| self.window.open_file(showing[idx]) | |
| # ----------------------------------------------------------------------------- | |
| # Git Utility | |
| # ----------------------------------------------------------------------------- | |
| def get_git_directory(view, cache={}, expire=10*60): | |
| path = view.file_name() | |
| if not path: | |
| return | |
| now = time() | |
| path = dirname(realpath(path)) | |
| if path in cache and cache[path]['age'] > now: | |
| return cache[path]['root'] | |
| temp, root = path, None | |
| while temp: | |
| if isdir(join(temp, '.git')): | |
| root = temp | |
| break | |
| temp = dirname(temp) | |
| cache[path] = {'root': root, 'age': now+expire} | |
| return root | |
| def normalise_repo_name(view): | |
| path = get_git_directory(view) | |
| if path: | |
| path = split(path) | |
| if len(path) == 2: | |
| return ' '.join([e.title() for e in path[1].split('-')]) | |
| # ----------------------------------------------------------------------------- | |
| # Snippets | |
| # ----------------------------------------------------------------------------- | |
| COPYRIGHT_HEADER = ( | |
| "%(comment)s Public Domain (-) " + str(datetime.utcnow().year) + | |
| """ The %(app)s Authors. | |
| %(comment)s See the %(app)s UNLICENSE file for details.""" | |
| ) | |
| GO_CMD = """%s | |
| package main | |
| import ( | |
| "$2" | |
| ) | |
| func main() { | |
| $0 | |
| } | |
| """ | |
| GO_PKG = """%s | |
| package $2 | |
| import ( | |
| "$3" | |
| ) | |
| func $4($5)$6 { | |
| $0 | |
| } | |
| """ | |
| GO_AN = "interface{}" | |
| GO_EF = """${1:f}, err ${2::=} ${4:some.Method}(${5:params}) | |
| if err != nil { | |
| ${6:body} | |
| return ${7:nil}, err | |
| } | |
| $0""" | |
| GO_MAP = "map[${1:string}]${2:string}" | |
| GO_FU = """func $1($2)$3 { | |
| $0 | |
| }""" | |
| GO_IN = """type $1 interface { | |
| $0 | |
| }""" | |
| GO_ME = """func ($1) $2($3)$4 { | |
| $0 | |
| }""" | |
| GO_ST = """type $1 struct { | |
| $0 | |
| }""" | |
| class AutoHeaderEventHandler(sublime_plugin.EventListener): | |
| def on_query_completions(self, view, prefix, locations): | |
| pt = locations[0] | |
| scopes = view.scope_name(pt).split() | |
| if 'source.go' not in scopes: | |
| return [] | |
| app = normalise_repo_name(view) | |
| if app: | |
| app = "${1:%s}" % app | |
| else: | |
| app = "$1" | |
| header = COPYRIGHT_HEADER % dict(comment="//", app=app) | |
| return [ | |
| ('cmd\tNew Command', GO_CMD % header), | |
| ('pkg\tNew Package', GO_PKG % header), | |
| ('error\tStandard Error', 'error'), | |
| ('an\tinteface{}', GO_AN), | |
| ('ef\tError Boilerplate', GO_EF), | |
| ('fu\tNew Function', GO_FU), | |
| ('in\tNew Interface', GO_IN), | |
| ('map\tNew Map', GO_MAP), | |
| ('me\tNew Method', GO_ME), | |
| ('st\tNew Struct', GO_ST), | |
| ('byte\t[]byte type', '[]byte'), | |
| ('int64\tint64 type', 'int64'), | |
| ('int\tint type', 'int'), | |
| ('int32\tint32 type', 'int32'), | |
| ('uint\tuint type', 'uint'), | |
| ('uint64\tuint64 type', 'uint64'), | |
| ('uint32\tuint32 type', 'uint32'), | |
| ('float64\tfloat64 type', 'float64'), | |
| ('float32\tfloat32 type', 'float32'), | |
| ('string\tstring type', 'string'), | |
| ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment