def on_query_completions(self, view, prefix, locations): pos = locations[0] scopes = view.scope_name(pos).split() if 'source.go' not in scopes: return [] # if we complete inside e.g. a map's key we're going to cause subtle bugs so bail if 'string.quoted.double.go' in scopes or 'string.quoted.single.go' in scopes or 'string.quoted.raw.go' in scopes: # afaik we must return something in order to disable st2's word completion return [(' ', '$0')] if not self.gocode_set: self.gocode_set = True # autostart the daemon gs.runcmd([gs.setting('gocode_cmd', 'gocode')]) # gocode is case-sesitive so push the location back to the 'dot' so it gives # gives us everything then st2 can pick the matches for us offset = pos - len(prefix) src = view.substr(sublime.Region(0, view.size())) fn = view.file_name() cl = self.complete(fn, offset, src) if scopes[-1] == 'source.go': cl.extend(gs.GLOBAL_SNIPPETS) elif scopes[-1] == 'meta.block.go' and ('meta.function.plain.go' in scopes or 'meta.function.receiver.go' in scopes): cl.extend(gs.LOCAL_SNIPPETS) return cl
def lint(self, view): self.rc -= 1 if self.rc == 0: err = '' cmd = gs.setting('gslint_cmd', 'gotype') real_path = view.file_name() pat_prefix = '' pwd = dirname(real_path) fn = basename(real_path) # normalize the path so we can compare it below real_path = pathjoin(pwd, fn) tmp_path = pathjoin(pwd, '.GoSublime~tmp~%d~%s~' % (view.id(), fn)) try: if cmd: files = [] if real_path: for fn in listdir(pwd): if fn.lower().endswith('.go'): fn = pathjoin(pwd, fn) if fn != real_path: files.append(fn) src = view.substr(sublime.Region(0, view.size())).encode('utf-8') if files: # m = LEADING_COMMENTS_PAT.sub('', src) m = LEADING_COMMENTS_PAT.match(src) m = PACKAGE_NAME_PAT.search(src, m.end(1) if m else 0) if m: pat_prefix = '^' + re.escape(tmp_path) with open(tmp_path, 'wb') as f: f.write(src) args = [cmd, '-p', m.group(1), tmp_path] args.extend(files) _, err = gs.runcmd(args) unlink(tmp_path) else: sublime.status_message('Cannot find PackageName') else: _, err = gs.runcmd([cmd], src) except Exception as e: sublime.status_message(str(e)) regions = [] view_id = view.id() self.errors[view_id] = {} for m in re.finditer(r'%s:(\d+):(\d+):\s+(.+)\s*$' % pat_prefix, err, re.MULTILINE): line, start, err = int(m.group(1))-1, int(m.group(2))-1, m.group(3) self.errors[view_id][line] = err pos = view.line(view.text_point(line, 0)).begin() + start if pos >= view.size(): pos = view.size() - 1 regions.append(sublime.Region(pos, pos)) if regions: flags = sublime.DRAW_EMPTY_AS_OVERWRITE view.add_regions('GsLint-errors', regions, 'invalid.illegal', 'cross', flags) else: view.erase_regions('GsLint-errors') self.on_selection_modified(view)
def complete(self, fn, offset, src): comps = [] cmd = gs.setting('gocode_cmd', 'gocode') can_pass_char_offset = gs.setting('gocode_accepts_character_offsets', False) if can_pass_char_offset is True: offset = 'c%s' % offset else: offset = gs.char_to_byte_offset(src, offset) args = [cmd, "-f=json", "autocomplete", fn, str(offset)] js, err = gs.runcmd(args, src) if err: sublime.error_message(err) else: try: js = json.loads(js) if js and js[1]: for ent in js[1]: if ent['name'] == 'main': continue etype = ent['type'] eclass = ent['class'] ename = ent['name'] tname = self.typeclass_prefix(eclass, etype) + ename if ent['class'] == 'func': comps.append(self.parse_decl_hack(etype, ename, tname)) elif ent['class'] != 'PANIC': comps.append((tname, ename)) except KeyError as e: sublime.error_message('Error while running gocode, possibly malformed data returned: %s' % e) except ValueError as e: sublime.error_message("Error while decoding gocode output: %s" % e) return comps
def run(self, edit): scopes = self.view.scope_name(0).split() if 'source.go' not in scopes: return region = sublime.Region(0, self.view.size()) src = self.view.substr(region) args = [gs.setting("gofmt_cmd", "gofmt"), "-d"] diff, err = gs.runcmd(args, src) if err: fn = self.view.file_name() err = err.replace('<standard input>', fn) def report_error(): sublime.status_message('GsFmt: File %s contains errors' % fn) sublime.set_timeout(report_error, 0) elif diff: err = '' try: edit = self.view.begin_edit() ed = SublimeEditor(self.view, edit) err = thatcher.patch(ed, diff) except Exception as e: err = "%s\n\n%s" % (err, e) finally: self.view.end_edit(edit) if err: def report_err(): self.view.run_command('undo') sublime.status_message("GsFmt: Could not patch the buffer: %s" % err) sublime.set_timeout(report_err, 0)
def do_hello(): global hello_sarting if hello_sarting: return hello_sarting = True tid = gs.begin(DOMAIN, 'Starting Gocode', False) call_cmd([mg9.GOCODE_BIN]) gs.end(tid) margo_cmd = list(gs.setting('margo_cmd', [])) margo_cmd = [ mg9.MARGO0_BIN, "-d", "-call", "replace", "-addr", gs.setting('margo_addr', '') ] tid = gs.begin(DOMAIN, 'Starting MarGo', False) out, err, _ = gs.runcmd(margo_cmd) gs.end(tid) out = out.strip() err = err.strip() if err: gs.notice(DOMAIN, err) elif out: gs.println(DOMAIN, 'MarGo started %s' % out) hello_sarting = False
def cb(): global hello_sarting if hello_sarting: return hello_sarting = True print 'starting gocode' call_cmd(['gocode']) margo_cmd = list(gs.setting('margo_cmd', [])) if not margo_cmd: err = 'Missing `margo_cmd`' gs.notice("MarGo", err) hello_sarting = False return margo_cmd.extend([ "-d", "-call", "replace", "-addr", gs.setting('margo_addr', '') ]) print 'starting margo' out, err, _ = gs.runcmd(margo_cmd) out = out.strip() err = err.strip() if err: gs.notice(DOMAIN, err) elif out: gs.notice(DOMAIN, 'MarGo started %s' % out) hello_sarting = False
def run(self, edit): if not gs.is_go_source_view(self.view): return region = sublime.Region(0, self.view.size()) src = self.view.substr(region) args = [gs.setting("gofmt_cmd", "gofmt"), "-d"] diff, err = gs.runcmd(args, src) if err: fn = self.view.file_name() err = err.replace('<standard input>', fn) gs.notice('GsFmt', 'File %s contains errors' % fn) elif diff: err = '' try: edit = self.view.begin_edit() ed = SublimeEditor(self.view, edit) err = thatcher.patch(ed, diff) except Exception as e: err = "%s\n\n%s" % (err, e) finally: self.view.end_edit(edit) if err: def cb(): if ed.dirty: self.view.run_command('undo') gs.notice("GsFmt", "Could not patch the buffer: %s" % err) sublime.set_timeout(cb, 0)
def f(): out, err, _ = gs.runcmd(['go', 'get', '-u', '-v', GOCODE_REPO, MARGO_REPO]) margo.bye_ni() call_cmd(['gocode', 'close']) gs.notice(DOMAIN, '%s done' % msg) gs.println(DOMAIN, '%s done\n%s%s' % (msg, out, err)) do_hello()
def do_hello(): global hello_sarting if hello_sarting: return hello_sarting = True tid = gs.begin(DOMAIN, 'Starting Gocode', False) call_cmd(['gocode']) gs.end(tid) margo_cmd = list(gs.setting('margo_cmd', [])) if margo_cmd: margo_cmd.extend([ "-d", "-call", "replace", "-addr", gs.setting('margo_addr', '') ]) tid = gs.begin(DOMAIN, 'Starting MarGo', False) out, err, _ = gs.runcmd(margo_cmd) gs.end(tid) out = out.strip() err = err.strip() if err: gs.notice(DOMAIN, err) elif out: gs.notice(DOMAIN, 'MarGo started %s' % out) hello_sarting = False else: err = 'Missing `margo_cmd`' gs.notice("MarGo", err) hello_sarting = False
def lint(self, view): self.rc -= 1 if self.rc == 0: cmd = gs.setting('gslint_cmd', 'gotype') if cmd: filelist = self.generate_filelist_for_lint(view) filelist = [cmd] + filelist _, err = gs.runcmd(filelist, "") else: err = '' lines = LINE_PAT.findall(err) regions = [] view_id = view.id() self.errors[view_id] = {} if lines: for m in lines: if m[0] == view.file_name(): #check if this error message is for the current file line, start, err = int(m[1])-1, int(m[2])-1, m[3] self.errors[view_id][line] = err lr = view.line(view.text_point(line, start)) regions.append(sublime.Region(lr.begin() + start, lr.end())) if regions: flags = sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED flags = sublime.DRAW_EMPTY_AS_OVERWRITE flags = sublime.DRAW_OUTLINED view.add_regions('GsLint-errors', regions, 'invalid.illegal', 'cross', flags) else: view.erase_regions('GsLint-errors') self.on_selection_modified(view)
def complete(self, fn, offset, src, func_name_only): comps = [] cmd = gs.setting('gocode_cmd', 'gocode') offset = 'c%s' % offset args = [cmd, "-f=json", "autocomplete", fn, offset] js, err, _ = gs.runcmd(args, src) if err: gs.notice('GsComplete', err) else: try: js = json.loads(js) if js and js[1]: for ent in js[1]: tn = ent['type'] cn = ent['class'] nm = ent['name'] sfx = self.typeclass_prefix(cn, tn) if cn == 'func': if nm in ('main', 'init'): continue act = gs.setting('autocomplete_tests', False) if not act and nm.startswith(('Test', 'Benchmark', 'Example')): continue params, ret = declex(tn) ret = ret.strip('() ') if func_name_only: a = nm else: a = [] for i, p in enumerate(params): n, t = p if t.startswith('...'): n = '...' a.append('${%d:%s}' % (i+1, n)) a = '%s(%s)' % (nm, ', '.join(a)) comps.append(('%s\t%s %s' % (nm, ret, sfx), a)) elif cn != 'PANIC': comps.append(('%s\t%s %s' % (nm, tn, sfx), nm)) except KeyError as e: gs.notice('GsComplete', 'Error while running gocode, possibly malformed data returned: %s' % e) except ValueError as e: gs.notice('GsComplete', "Error while decoding gocode output: %s" % e) return comps
def post(path, a, default, fail_early=False): resp = None try: params = urllib.urlencode({"data": json.dumps(a)}) headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "application/json; charset=utf-8"} try: resp = conn.post(path, params, headers) except Exception: if fail_early: return (default, traceback.format_exc()) margo_cmd = list(gs.setting("margo_cmd", [])) if not margo_cmd: err = "Missing `margo_cmd`" gs.notice("MarGo", err) return (default, err) margo_cmd.extend(["-d", "-addr", gs.setting("margo_addr", "")]) out, err, _ = gs.runcmd(margo_cmd) out = out.strip() if out: print("MarGo: started: %s" % out) err = err.strip() if err: gs.notice("MarGo", err) else: resp = conn.post(path, params, headers) except: err = traceback.format_exc() gs.notice("MarGo", err) return (default, err) if not isinst(resp, {}): resp = {} if not isinst(resp.get("error"), u""): resp["error"] = "Invalid Response" if default is not None and not isinst(resp.get("data"), default): resp["data"] = default if not resp["error"]: resp["error"] = "Invalid Data" return (resp["data"], resp["error"])
def lint(self): view = self.view pos = view.sel()[0].begin() scopes = set(self.view.scope_name(pos).split()) if 'source.go' in scopes and self.ignored_scopes.isdisjoint(scopes): err = '' out = '' cmd = gs.setting('gslint_cmd', 'gotype') real_path = view.file_name() src = view.substr(sublime.Region(0, view.size())).encode('utf-8') if not real_path or not src: return pat_prefix = '' cwd = getcwd() pwd = dirname(real_path) chdir(pwd) real_fn = basename(real_path) # normalize the path so we can compare it below real_path = pathjoin(pwd, real_fn) tmp_path = pathjoin(pwd, '.GoSublime~tmp~%d~%s~' % (view.id(), real_fn)) try: real_fn_lower = real_fn.lower() x = gs.GOOSARCHES_PAT.match(real_fn_lower) x = x.groups() if x else None if x and cmd: files = [tmp_path] for fn in listdir(pwd): fn_lower = fn.lower() y = gs.GOOSARCHES_PAT.match(fn_lower) y = y.groups() if y else None if y and fn_lower != real_fn_lower: path = pathjoin(pwd, fn) # attempt to resolve any os-specific file names... # [0] => fn prefix, [1] => os, [2] => arch if (x[0] != y[0]) or (x[1] == y[1] and (not x[2] or not y[2] or x[2] == y[2])): files.append(path) pkg = 'main' m = LEADING_COMMENTS_PAT.match(src) m = PACKAGE_NAME_PAT.search(src, m.end(1) if m else 0) if m: pat_prefix = '^' + re.escape(tmp_path) with open(tmp_path, 'wb') as f: f.write(src) t = { "$pkg": [m.group(1)], "$files": files, "$path": tmp_path, "$real_path": real_path } args = [] for i in list(cmd): args.extend(t.get(i, [i])) out, err = gs.runcmd(args) unlink(tmp_path) except Exception: gs.notice("GsLintThread: Cmd", traceback.format_exc()) chdir(cwd) regions = [] errors = {} if err: err = LINE_INDENT_PAT.sub(' ', err) for m in re.finditer(r'%s[:](\d+)(?:[:](\d+))?[:](.+)$' % pat_prefix, err, re.MULTILINE): line = int(m.group(1))-1 start = 0 if m.group(2) == '' else int(m.group(2))-1 err = m.group(3).strip() errors[line] = err pos = view.line(view.text_point(line, 0)).begin() + start if pos >= view.size(): pos = view.size() - 1 regions.append(sublime.Region(pos, pos)) self.gslint.set_errors(view, errors) if regions: flags = sublime.DRAW_EMPTY_AS_OVERWRITE view.add_regions('GsLint-errors', regions, 'invalid.illegal', 'cross', flags) else: view.erase_regions('GsLint-errors')
def f(): out, err, _ = gs.runcmd(['go', 'get', '-u', '-v', GOCODE_REPO, MARGO_REPO]) margo.bye_ni() call_cmd(['gocode', 'close']) gs.notice(DOMAIN, '%s done\n%s%s' % (msg, out, err)) gsq.dispatch(hello, 'Starting MarGo and gocode...', view)
def lint(self): err = "" out = "" with self.sem: cmd = self.cmd view_id = self.view_id real_path = self.view_real_path src = self.view_src.encode("UTF-8") view = self.view self.clear() if not (real_path and src): return pat_prefix = "" cwd = getcwd() pwd = dirname(real_path) chdir(pwd) real_fn = basename(real_path) # normalize the path so we can compare it below real_path = pathjoin(pwd, real_fn) tmp_path = pathjoin(pwd, ".GoSublime~tmp~%d~%s~" % (view_id, real_fn)) try: real_fn_lower = real_fn.lower() x = gs.GOOSARCHES_PAT.match(real_fn_lower) x = x.groups() if x else None if x and cmd: files = [tmp_path] for fn in listdir(pwd): fn_lower = fn.lower() y = gs.GOOSARCHES_PAT.match(fn_lower) y = y.groups() if y else None if y and fn_lower != real_fn_lower: path = pathjoin(pwd, fn) # attempt to resolve any os-specific file names... # [0] => fn prefix, [1] => os, [2] => arch if (x[0] != y[0]) or (x[1] == y[1] and (not x[2] or not y[2] or x[2] == y[2])): files.append(path) pkg = "main" m = LEADING_COMMENTS_PAT.match(src) m = PACKAGE_NAME_PAT.search(src, m.end(1) if m else 0) if m: pat_prefix = "^" + re.escape(tmp_path) with open(tmp_path, "wb") as f: f.write(src) t = {"$pkg": [m.group(1)], "$files": files, "$path": tmp_path, "$real_path": real_path} args = [] for i in list(cmd): args.extend(t.get(i, [i])) out, err = gs.runcmd(args) unlink(tmp_path) except Exception: gs.notice("GsLintThread: Cmd", traceback.format_exc()) chdir(cwd) errors = {} if err: err = LINE_INDENT_PAT.sub(" ", err) for m in re.finditer(r"%s[:](\d+)(?:[:](\d+))?[:](.+)$" % pat_prefix, err, re.MULTILINE): row = int(m.group(1)) - 1 col = 0 if m.group(2) == "" else int(m.group(2)) - 1 err = m.group(3).strip() errors[row] = ErrorReport(row, col, err) def cb(): regions = [] for k in errors: er = errors[k] line = view.line(view.text_point(er.row, 0)) pos = line.begin() + er.col if pos >= line.end(): pos = line.end() regions.append(sublime.Region(pos, pos)) gs.l_errors[view.id()] = errors if regions: flags = sublime.DRAW_EMPTY_AS_OVERWRITE view.add_regions("GsLint-errors", regions, "invalid.illegal", "bookmark", flags) else: view.erase_regions("GsLint-errors") # update the view so the error is displayed without needing to move the cursor describe_errors() set_timeout(vsync, 250) set_timeout(cb, 0)
def run(self, edit): view = self.view pt = view.sel()[0].begin() if view.substr(sublime.Region(pt - 1, pt)) == '(': depth = 1 else: depth = 0 c = '' while True: line = view.line(pt) scope = view.scope_name(pt) if 'string' in scope or 'comment' in scope: pt = view.extract_scope(pt).begin() - 1 continue c = view.substr(sublime.Region(pt - 1, pt)) if not c: pt = -1 break if c.isalpha() and depth >= 0: while c.isalpha() or c == '.': pt += 1 c = view.substr(sublime.Region(pt - 1, pt)) # curly braces ftw break # break outer while loop if c == ')': depth -= 1 elif c == '(': depth += 1 i = pt while True: pc = view.substr(sublime.Region(i - 1, i)) if pc == '.' or pc.isalpha(): i -= 1 else: break if i != pt: pt = i continue pt -= 1 if pt <= line.begin(): pt = -1 break while not c.isalpha() and pt > 0: pt -= 1 c = view.substr(sublime.Region(pt - 1, pt)) if pt <= 0 or view.scope_name(pt).strip() == 'source.go': self.show_hint("// can't find selector") return line = view.line(pt) line_start = line.begin() s = view.substr(line) if not s: self.show_hint('// no source') return scopes = [ 'support.function.any-method.go', 'meta.function-call.go', 'support.function.builtin.go', ] found = False while True: scope = view.scope_name(pt).strip() for s in scopes: if scope.endswith(s): found = True break if found or pt <= line_start: break pt -= 1 if not found: self.show_hint("// can't find function call") return s = view.substr(sublime.Region(line_start, pt)) m = END_SELECTOR_PAT.match(s) if not m: self.show_hint("// can't match selector") return offset = (line_start + m.end()) coffset = 'c%d' % offset sel = m.group(1) name = m.group(2) candidates = [] src = view.substr(sublime.Region(0, view.size())) fn = view.file_name() or '<stdin>' cmd = gs.setting('gocode_cmd', 'gocode') args = [cmd, "-f=json", "autocomplete", fn, coffset] js, err, _ = gs.runcmd(args, src) if err: gs.notice(DOMAIN, err) else: try: js = json.loads(js) if js and js[1]: candidates = js[1] except: pass c = {} for i in candidates: if i['name'] == name: if c: c = None break c = i if not c: self.show_hint('// no candidates found') return s = '// %s %s\n%s' % (c['name'], c['class'], c['type']) self.show_hint(s)
def run(self, edit): view = self.view pt = gs.sel(view).begin() if view.substr(sublime.Region(pt-1, pt)) == '(': depth = 1 else: depth = 0 c = '' while True: line = view.line(pt) scope = view.scope_name(pt) if 'string' in scope or 'comment' in scope: pt = view.extract_scope(pt).begin() - 1 continue c = view.substr(sublime.Region(pt-1, pt)) if not c: pt = -1 break if c.isalpha() and depth >= 0: while c.isalpha() or c == '.': pt += 1 c = view.substr(sublime.Region(pt-1, pt)) # curly braces ftw break # break outer while loop if c == ')': depth -= 1 elif c == '(': depth += 1 i = pt while True: pc = view.substr(sublime.Region(i-1, i)) if pc == '.' or pc.isalpha(): i -= 1 else: break if i != pt: pt = i continue pt -= 1 if pt <= line.begin(): pt = -1 break while not c.isalpha() and pt > 0: pt -= 1 c = view.substr(sublime.Region(pt-1, pt)) if pt <= 0 or view.scope_name(pt).strip() == 'source.go': self.show_hint("// can't find selector") return line = view.line(pt) line_start = line.begin() s = view.substr(line) if not s: self.show_hint('// no source') return scopes = [ 'support.function.any-method.go', 'meta.function-call.go', 'support.function.builtin.go', ] found = False while True: scope = view.scope_name(pt).strip() for s in scopes: if scope.endswith(s): found = True break if found or pt <= line_start: break pt -= 1 if not found: self.show_hint("// can't find function call") return s = view.substr(sublime.Region(line_start, pt)) m = END_SELECTOR_PAT.match(s) if not m: self.show_hint("// can't match selector") return offset = (line_start + m.end()) coffset = 'c%d' % offset sel = m.group(1) name = m.group(2) candidates = [] src = view.substr(sublime.Region(0, view.size())) fn = view.file_name() or '<stdin>' cmd = gs.setting('gocode_cmd', 'gocode') args = [cmd, "-f=json", "autocomplete", fn, coffset] js, err, _ = gs.runcmd(args, src) if err: gs.notice(DOMAIN, err) else: try: js = json.loads(js) if js and js[1]: candidates = js[1] except: pass c = {} for i in candidates: if i['name'] == name: if c: c = None break c = i if not c: self.show_hint('// no candidates found') return s = '// %s %s\n%s' % (c['name'], c['class'], c['type']) self.show_hint(s)
def call_cmd(cmd): _, _, exc = gs.runcmd(cmd) return not exc