def prepare_payload(self): src = src_paths(self.nvim) test = test_paths(self.nvim) path = current_file(self.nvim) root_path = current_path(self.nvim) rel_path = os.path.relpath(path, start=root_path).split('/') open_with = self.nvim.vars.get( 'acid_open_alternate_file_with', self.nvim.vars.get('acid_open_new_file_with', 'edit') ) if rel_path[0] in src: log_debug("Current file is a 'src', changing to 'test'") alt_path = to_alt_path( rel_path, test, root_path, lambda f: '{}_test'.format(f), 'test' ) else: log_debug("Current file is a 'test', changing to 'src'") alt_path = to_alt_path( rel_path, src, root_path, lambda f: f.split('_')[0], 'src' ) if os.path.exists(alt_path): self.nvim.command('silent {} {}'.format(open_with, alt_path)) else: ns = path_to_ns(alt_path, test | src) self.nvim.command('AcidNewFile {}'.format(ns)) return None
def format_dict(d): lines = [] for k, v in d.items(): if type(v) == dict: data = format_dict(v) elif type(v) == list: data = v else: data = [v] log_debug("Pre-parsed data: {}", str(data)) if not data: lines.append("{: <10} → []".format(k)) else: i, *j = data lines.append("{: <10} → {}".format(k, str(i).replace('\n', ''))) [ lines.append("{: <12} {}".format("", str(l).replace('\n', ''))) for l in j ] log_debug("Produced {} lines", len(lines)) return lines
def ensure_cmd_win_exists(self): use_cmd_win = bool( self.nvim.vars.get('acid_meta_repl_use_cmd_window', False)) log_debug("use cmd win? is {}", self.use_cmd_win) if use_cmd_win: no_cmd = self.cmd_buf_nr is None has_no_cmd_window = self.nvim.funcs.bufwinnr(self.cmd_buf_nr) == -1 if no_cmd or has_no_cmd_window: send = """:call AcidSendNrepl({ 'op': 'eval', 'code': join(getline(1, '$'), '\\n') }, 'MetaRepl')<CR>""".splitlines() send = "map <buffer> <silent> <localleader><CR> {}".format( "".join(map(str.strip, send))) meta_repl_window = self.nvim.funcs.bufwinnr(self.buf_nr) nvim.command("{} wincmd w".format(meta_repl_window)) self.cmd_buf_nr = build_window( self.nvim, close=1, throwaway=1, orientation="rightbelow 20 split", commands=[ 'file acid://meta-repl-{}/scratchpad'.format( self.random), 'set ft=clojure', send, "let b:acid_ns_strategy='ns:user'" ])
def existing(ap): alt_root = os.path.join(root, ap) if os.path.exists(alt_root): log_debug("Path {} exists", alt_root) return os.path.join(alt_root, *path) log_debug("Path {} doesn't exist", alt_root) return
def path_to_ns(path, stop_paths=None): if stop_paths is None: stop_paths = ['src', 'test'] stop_paths = sorted(stop_paths, key=lambda x: x.count('/')) raw_path_list = None for stop_path in reversed(stop_paths): m = re.search(stop_path, path) if m: raw_path_list = path[m.start():].replace( "_", "-").split('/')[stop_path.count('/') + 1:] raw_path_list[-1] = raw_path_list[-1].split('.')[0] break if raw_path_list is None: log_debug("Previous check did not work. Attempting project.clj") # Look for project.clj path = path.replace("_", "-").split('/')[1:] path[-1] = path[-1].split('.')[0] for ix, _ in enumerate(path): if os.path.exists(os.path.join(*["/", *path[:ix], "project.clj"])): raw_path_list = path[ix + 1:] break if raw_path_list is None: log_warning("Have not found any viable path") return None else: log_debug("Found path list: {}", raw_path_list) return ".".join(raw_path_list)
def acid_alternate_file(self, args): try: src = src_paths(self.nvim) path = get(args, 0, self.nvim.funcs.expand("%:p")) log_info("Finding alternate file for {}", path) root_path = self.nvim.funcs.getcwd() rel_path = os.path.relpath(path, start=root_path).split('/') if rel_path[0] in src: paths = alt_paths( rel_path, test_paths(self.nvim), root_path, lambda f: '{}_test'.format(f), ) else: paths = alt_paths(rel_path, src, root_path, lambda f: "_".join(f.split('_')[:-1]), 'src') except Exception as e: log_debug("error: {}", e) paths = [] log_debug("paths: {}", paths) return list(paths)
def on_handle(self, msg, *_): if 'no-info' in msg.get('status', []): warning(self.nvim, "No information for symbol") return try: lines = self.transform(msg) except Exception as e: warning(self.nvim, "Couldn't transform msg into doc.") log_error(e) return no_doc_buffer = self.doc_buf_nr is None buf_win_nr = self.nvim.funcs.bufwinnr(self.doc_buf_nr) doc_len = len(lines) if no_doc_buffer or buf_win_nr == -1: cmds = ['file acid://doc', 'wincmd p'] self.doc_buf_nr = build_window( self.nvim, close=1, commands=cmds, throwaway=1, orientation="leftabove {} split".format(doc_len)) else: self.nvim.command('{} wincmd w | resize {} | wincmd p'.format( buf_win_nr, doc_len)) log_debug(lines) self.nvim.buffers[self.doc_buf_nr][:] = lines
def list_clj_files(nvim): rtp = nvim.options.get('runtimepath').split(',') for path in rtp: match = os.path.join(path, 'clj/acid/**/*.clj') log_debug('Attempting path: {}', match) yield from glob.iglob(match)
def path_to_ns(nvim, force=False): fpath = nvim.funcs.expand("%:p:r") if fpath in path_ns_cache and not force: ns = path_ns_cache[fpath] log_debug("Hitting cache for ns '{}'", ns) return ns stop_paths = get_stop_paths(nvim) ns = pure.path_to_ns(fpath, stop_paths) path_ns_cache[fpath] = ns return ns
def path_to_ns(nvim, fpath=None, force=False): if not fpath: fpath = nvim.funcs.expand("%:p:r") if fpath in path_ns_cache and not force: ns = path_ns_cache[fpath] return ns log_debug("Namespace is not cached. Finding from path") stop_paths = get_stop_paths(nvim) ns = pure.path_to_ns(fpath, stop_paths) path_ns_cache[fpath] = ns return ns
def path_to_ns(path, stop_paths=None, base_files=None): log_debug("Supplied path is {}", str(path)) if not path: log_debug("Possibly empty or scratch buffer. Skipping") return if stop_paths is None: stop_paths = ['src', 'test'] if base_files is None: base_files = ['project.clj', 'deps.edn', 'build.boot'] stop_paths = sorted(stop_paths, key=lambda x: x.count('/')) raw_path_list = None for stop_path in reversed(stop_paths): stop_path = "/{}/".format(stop_path) ix = path[::-1].find(stop_path[::-1]) log_debug("Attempting reverse match: [{}: {}] -> {}", stop_path[::-1], path[::-1], ix) if ix > 0: startpos = len(path) - ix raw_path_list = path[startpos:].replace("_", "-").split('/') raw_path_list = [x for x in raw_path_list if x] if len(raw_path_list) > 0: raw_path_list[-1] = raw_path_list[-1].split('.')[0] break if raw_path_list is None: log_debug("Previous check did not work. Attempting base files") # Look for project.clj path = path.replace("_", "-").split('/')[1:] path[-1] = path[-1].split('.')[0] for ix, _ in enumerate(path): for bf in base_files: if os.path.exists(os.path.join(*["/", *path[:ix], bf])): raw_path_list = path[ix+1:] break if not raw_path_list: log_warning("Have not found any viable path") return "" else: log_debug("Found path list: {}", raw_path_list) return ".".join(raw_path_list)
def to_alt_path(path_arr, alt_paths, root, rename_fn, default): # clone array so we don't overwrite last element path = list(path_arr)[1:] path[-1] = rename_file(path[-1], rename_fn) for ap in alt_paths: fname = os.path.join(root, ap, *path) if os.path.exists(fname): log_debug("Alternate file exists. using '{}'", fname) return fname fname = os.path.join(root, default, *path) log_debug("Alternate doesn't exist. using '{}'", fname) # Returns default path if no test is found return fname
def find_file_in_path(nvim, fname, resource=None): log_debug("finding path") protocol, *_, fpath = fname.split(':') log_debug("Finding path to {}", fname) if protocol == 'file': if os.path.exists(fpath): return fpath elif resource != None: paths = get_stop_paths(nvim) for path in paths: attempt = os.path.join(path, resource) if os.path.exists(attempt): return attempt project = resource.split('/')[0] foreign_project_fpath = nvim.vars.get('acid_project_root', None) if foreign_project_fpath is None: return for path in paths: attempt = os.path.join(foreign_project_fpath, project, path, resource) if os.path.exists(attempt): return attempt elif protocol == 'jar': jarpath, fpath = fpath.split('!') hashed = '{:X}'.format( binascii.crc32(bytes(jarpath, 'ascii')) & 0xffffffff) tmppath = os.path.join(tempfile.gettempdir(), hashed) if not os.path.exists(tmppath): os.mkdir(tmppath) zipf = zipfile.ZipFile(jarpath) zipf.extractall(tmppath) zipf.close() fpath = fpath if not os.path.isabs(fpath) else fpath[1:] full = os.path.join(tmppath, fpath) if os.path.exists(full): return full return None
def alt_paths(path_arr, alt_paths, root, rename_fn): # clone array so we don't overwrite last element path = list(path_arr)[1:] path[-1] = pure.rename_file(path[-1], rename_fn) for ap in alt_paths: fname = os.path.join(root, ap, *path) if os.path.exists(fname): log_debug("Alternate file exists. using '{}'", fname) return fname def existing(ap): alt_root = os.path.join(root, ap) if os.path.exists(alt_root): return os.path.join(alt_root, *path) return filter(lambda i: i is not None, map(existing, alt_paths))
def print_doc(msg): outcome = {} lines = [] for key, value in definition['data'].items(): log_debug("Working with key {}", key) if 'default' in value: obj = msg.get(key, value['default']) else: obj = msg[key] if obj: if 'transform' in value: this, *other = transform_meta(value['transform']) obj = value['transform'](obj, *[outcome[i] for i in other]) if 'prepend' in value: prepend = value['prepend'] if type(obj) == list: obj = [prepend, *obj] else: obj = '{} {}'.format(prepend, obj) if 'rename' in value: key = value['rename'] outcome[key] = obj log_debug("current data: {}", outcome) for key in definition['format']: if type(key) == list and lines[-1] != '': lines.append('') elif key in outcome: obj = outcome[key] if obj: obj_type = type(obj) if obj_type == str: lines.append(obj) elif obj_type == list: lines = [*lines, *obj] else: log_warning('Unknown obj type, skipping.') return lines
def repl_host_address(nvim): path = current_path(nvim) connection = nvim.exec_lua("return require('acid.connections').get(...)", path) if connection is not None: return connection log_debug("Failed to connect from lua connections.") host = nvim.vars.get('acid_nrepl_host', '127.0.0.1') try: addr = [host, get_port_no(nvim)] nvim.exec_lua("require('acid.connections').set(...)", path, addr, async_=True) log_debug("Found a .nrepl-port file, using that") return addr except: return None
def repl_host_address(nvim): path = current_path(nvim) if path[-1] != "/": path = path + "/" ix = nvim.funcs.luaeval("require('acid.connections').current[_A]", path) if ix != None: connection = nvim.funcs.luaeval( "require('acid.connections').store[_A]", ix) log_debug("Return from lua: {}", str(connection)) return connection host = nvim.vars.get('acid_lein_host', '127.0.0.1') try: return [host, get_port_no(nvim)] except: return None
def prepare_payload(self, ns): files = list(list_clj_files(self.nvim)) path = '{}.clj'.format(ns_to_path(ns)) log.log_debug('Found all this clojure files: {}', files) log.log_debug('Attempting to match against {}', path) match = list(filter(lambda k: k.endswith(path), files)) if any(match): fpath, *_ = match fpath = os.path.relpath(fpath, start=current_path(self.nvim)) with open(fpath, 'r') as source: data = '\n'.join(source.readlines()) return { 'file': data, 'file-path': fpath, 'file-name': os.path.basename(fpath) } else: log.warning(self.nvim, 'no file found!')
def ensure_win_exists(self): no_shared_buffer = self.buf_nr is None has_no_window = no_shared_buffer or self.nvim.funcs.bufwinnr( self.buf_nr) == -1 log_debug("buf_nr is {}", self.buf_nr) log_debug("has window? {}", has_no_window) if no_shared_buffer or has_no_window: self.random = random.randint(0, 100) cmds = [ 'file acid://meta-repl-{}'.format(self.random), 'nnoremap <buffer> <localleader><CR> :e<CR>', 'nnoremap <buffer> <localleader><localleader> kdggjdG', 'nnoremap <buffer> <localleader>D kdgg', 'nnoremap <buffer> <localleader>d jdG', ] self.buf_nr = build_window( self.nvim, close=1, commands=cmds, throwaway=1, ) log_debug("Set buf_nr to {}", self.buf_nr)
def path_to_ns(nvim): path = nvim.funcs.expand("%:p:r").replace("_", "-").split('/')[1:] raw_path_list = None for ix, node in enumerate(reversed(path)): if node == 'src': raw_path_list = path[ix * -1:] break if raw_path_list is None: # Look for project.clj for ix, _ in enumerate(path): if os.path.exists(os.path.join(*["/", *path[:ix], "project.clj"])): raw_path_list = path[ix + 1:] break if raw_path_list is None: log_warning("Have not found any viable path") else: log_debug("Found path list: {}", raw_path_list) return ".".join(raw_path_list)
def new_file(self, args): ns = args[0] has_path = len(args) > 1 if not has_path: fname = "{}.clj".format(ns_to_path(ns)) base = 'test' if ns.endswith('-test') else 'src' path = os.path.join(current_path(self.nvim), base, fname) else: path = args[1] if os.path.exists(path): log_debug("File already exists. Aborting.") return path directory = os.path.dirname(path) if not os.path.exists(directory): os.makedirs(directory) with open(path, 'w') as fpath: fpath.write('(ns {})'.format(ns)) return path
def add_persistent_watch(self, url, handler, matches={}): "Adds a callback to all messages in a connection." watcher_key = "{}-persistent".format(handler.name) conn = self.get_or_create(url) if not watcher_key in self.persistent[url]: log.log_info('Adding new persisntent watcher fn: {}', handler.name) self.persistent[url].add(watcher_key) log.log_debug('persistent handler -> {}', str(handler)) log.log_debug('connection -> {}', str(url)) log.log_debug('key -> {}', str(watcher_key)) patched_handler = handler.gen_handler(finalize_watch) conn.watch(watcher_key, matches, patched_handler)
def format_payload(payload): if type(payload) == str: return [payload] ls = [] try: msg_id = payload.get('id', '****') for k, v in payload.items(): key = k.lower() if key not in {'ns', 'session', 'id', 'op'}: if type(v) == list: log_debug('v is a list') header, trailer = v[0], v[1:] elif type(v) == dict: log_debug('v is a dict') formatted = format_dict(v) log_debug('Got {}', str(formatted)) if len(formatted) > 0: header, *trailer = formatted else: header = [] elif '\n' in v: header, *trailer = v.split('\n') else: header, trailer = v, [] if not header: next if header.isspace() or header is "": header, trailer = trailer[0], trailer[1:] ls.append("[{}][{: <9}] => {}".format( str(msg_id)[-4:], key.upper(), str(header) ).strip()) for i in trailer: ls.append("{: <20} {}".format("", str(i))) except e: log_error("Couldn't finish producing output: {}", str(e)) finally: if len(ls) == 0: log_warning("Empty output for ls: {}", str(payload)) return ls
def on_handle(self, msg, *_): if not 'no-info' in msg.get('status', []): name = msg['name'] ns = msg.get('ns', '') arglist = msg.get('arglists-str', []) doc = msg.get('doc', '') javadoc = msg.get('javadoc', '') added = msg.get('added', '') super_ = msg.get('super', '') modifiers = msg.get('modifiers', []) see_also = msg.get('see-also', []) interfaces = msg.get('interfaces', []) if arglist: fn_calls = ["({}{})".format(name, " {}".format(i) if i else "") for i in arglist[2:-2].split('] [')] else: fn_calls = [name] if see_also: see_also = ["https://clojuredocs.org/{}".format(i) for i in see_also] docl = [i for i in [ " ".join(fn_calls), ns, modifiers, " ", javadoc, *doc.split('\n'), " ", added and "Since version {}".format(added), interfaces and "Implements: {}".format( ",".join(interfaces) ) or "", super_ and "Extends: {}".format(super_) or "", see_also and "See also:" or "", *see_also, ] if i ] no_doc_buffer = self.doc_buf_nr is None buf_win_nr = self.nvim.funcs.bufwinnr(self.doc_buf_nr) doc_len = len(docl) if no_doc_buffer or buf_win_nr == -1: cmds = ['file acid://doc', 'wincmd p', ] self.doc_buf_nr = build_window( self.nvim, close=1, commands=cmds, throwaway=1, orientation="leftabove {} split".format(doc_len) ) else: self.nvim.command('{} wincmd w | resize {} | wincmd p'.format( buf_win_nr, doc_len )) info(self.nvim, "Documentation for {}/{}".format(ns, name)) log_debug(docl) exec_cmd = "bd {} | au! AcidDoc".format(self.doc_buf_nr) self.nvim.buffers[self.doc_buf_nr][:] = docl self.nvim.command('augroup AcidDoc') self.nvim.command('au!') self.nvim.command( 'au CursorMoved * exec "{}"'.format(exec_cmd)) self.nvim.command('augroup END') else: warning(self.nvim, "No information for symbol")
def on_configure(self, *_a, **_k): log.log_debug('Passing spec transformation fn') return [doc_transform(definition)]
def on_configure(self, transform, *args, **kwargs): log_debug('Got {} as transform fn', transform) self.transform = transform