def _restore(nvim: Nvim, win: Window, buf: Buffer, pos: NvimPos) -> Tuple[str, Optional[int]]: row, _ = pos ns = create_ns(nvim, ns=NS) marks = tuple(buf_get_extmarks(nvim, buf=buf, id=ns)) if len(marks) != 2: return "", 0 else: m1, m2 = marks after, *_ = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) cur_row, cur_col = win_get_cursor(nvim, win=win) (_, lo), (_, hi) = m1.end, m2.begin binserted = encode(after)[lo:hi] inserted = decode(binserted) movement = cur_col - lo if cur_row == row and lo <= cur_col <= hi else None if inserted: buf_set_text(nvim, buf=buf, begin=m1.end, end=m2.begin, text=("", )) return inserted, movement
def _word(nvim: Nvim, is_inside: bool) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, c = win_get_cursor(nvim, win=win) lines = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) line = next(iter(lines)) bline = line.encode() # position under cursor c = min(len(bline) - 1, c) col = len(bline[:c].decode()) + 1 lhs, rhs = line[:col], line[col:] # undo col + 1 offset = len(next(reversed(lhs), "").encode()) ctx = gen_split(lhs, rhs, unifying_chars=UNIFIYING_CHARS) if not (ctx.word_lhs + ctx.word_rhs): words_lhs, words_rhs = ctx.syms_lhs, ctx.syms_rhs else: words_lhs, words_rhs = ctx.word_lhs, ctx.word_rhs c_lhs = c + offset - len(words_lhs.encode()) c_rhs = c + offset + len(words_rhs.encode()) - 1 if is_inside: mark1 = (row, c_lhs) mark2 = (row, c_rhs) else: mark1 = (row, c_lhs - 1) mark2 = (row, c_rhs + 1) set_visual_selection(nvim, win=win, mode="v", mark1=mark1, mark2=mark2)
def _word(nvim: Nvim, is_inside: bool) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, col = win_get_cursor(nvim, win=win) line, *_ = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) bline = encode(line) lhs, rhs = decode(bline[:col]), decode(bline[col:]) ctx = gen_split(lhs, rhs, unifying_chars=UNIFIYING_CHARS) if not (ctx.word_lhs + ctx.word_rhs): words_lhs, words_rhs = ctx.syms_lhs, ctx.syms_rhs else: words_lhs, words_rhs = ctx.word_lhs, ctx.word_rhs c_lhs = max(col - len(encode(words_lhs)), 0) c_rhs = max(col + len(encode(words_rhs)) - 1, 0) if is_inside: mark1 = (row, c_lhs) mark2 = (row, c_rhs) else: mark1 = (row, max(0, c_lhs - 1)) mark2 = (row, min(len(bline), c_rhs + 1)) set_visual_selection(nvim, win=win, mode="v", mark1=mark1, mark2=mark2)
def it() -> Iterator[Tuple[Window, Tuple[int, int]]]: wins = list_wins(nvim) for win in wins: buf = win_get_buf(nvim, win=win) if buf == ctx.buf: row, col = win_get_cursor(nvim, win) yield win, (row, col)
def _surround(nvim: Nvim) -> None: lhs: str = nvim.vvars["char"] rhs = _CHAR_PAIRS.get(lhs) if rhs: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, col = win_get_cursor(nvim, win=win) lines = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) line = next(iter(lines)) def cont() -> None: new_col = col + len(lhs.encode()) nvim.api.set_vvar("char", lhs + cast(str, rhs)) set_cur = lambda: win_set_cursor( nvim, win=win, row=row, col=new_col) go(async_call(nvim, set_cur)) if rhs == lhs: is_even = line.count(lhs) % 2 == 0 if is_even: cont() else: counts = Counter(line) if counts[lhs] >= counts[rhs]: cont()
def _marks(nvim: Nvim, ns: int, win: Window, buf: Buffer) -> Iterator[ExtMark]: cursor = win_get_cursor(nvim, win=win) for idx, mark in enumerate(_ls_marks(nvim, ns=ns, buf=buf)): if not idx and mark.begin == cursor and mark.end == cursor: _del_marks(nvim, buf=buf, id=ns, marks=(mark, )) else: yield mark
def _restore_pos(nvim: Nvim) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, _ = win_get_cursor(nvim, win=win) pos: Optional[int] = buf_get_var(nvim, buf=buf, key=BUF_VAR_NAME) if pos is not None: win_set_cursor(nvim, win=win, row=row, col=pos)
def _comment_single(nvim: Nvim) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) if not writable(nvim, buf=buf): return else: row, _ = win_get_cursor(nvim, win=win) lines = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) lhs, rhs = buf_commentstr(nvim, buf=buf) new_lines = _toggle_comment(lhs, rhs, lines=lines) buf_set_lines(nvim, buf=buf, lo=row, hi=row + 1, lines=new_lines)
def _line(nvim: Nvim, is_inside: bool) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, _ = win_get_cursor(nvim, win=win) lines = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) line = next(iter(lines)) lhs, rhs = (_p_inside if is_inside else _p_around)(line) set_visual_selection(nvim, win=win, mode="v", mark1=(row, lhs), mark2=(row, rhs))
def _rename(nvim: Nvim) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, col = win_get_cursor(nvim, win=win) line, *_ = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) b_line = encode(line) lhs, rhs = decode(b_line[:col]), decode(b_line[col:]) split = gen_split(lhs=lhs, rhs=rhs, unifying_chars=UNIFIYING_CHARS) word = split.word_lhs + split.word_rhs ans = ask(nvim, question=LANG("rename: "), default=word) if ans: nvim.lua.vim.lsp.buf.rename(ans)
def redraw(nvim: Nvim, state: State, focus: Optional[PurePath]) -> None: focus_row = state.derived.path_row_lookup.get(focus) if focus else None ns = nvim.api.create_namespace(FM_NAMESPACE) use_extmarks = nvim.funcs.has("nvim-0.6") for win, buf in find_fm_windows(nvim): p_count = buf_line_count(nvim, buf=buf) n_count = len(state.derived.lines) row, col = win_get_cursor(nvim, win=win) (r1, c1), (r2, c2) = operator_marks(nvim, buf=buf, visual_type=None) try: hashed_lines = _DECODER( buf_get_var(nvim, buf=buf, key=_FM_HASH_VAR)) except DecodeError: hashed_lines = ("", ) if focus_row is not None: new_row: Optional[int] = focus_row + 1 elif row >= n_count: new_row = n_count elif p_count != n_count: new_row = row + 1 else: new_row = None a1 = Atomic() a1.buf_set_option(buf, "modifiable", True) a2 = _update( use_extmarks, buf=buf, ns=ns, derived=state.derived, hashed_lines=hashed_lines, ) a3 = Atomic() a3.buf_set_option(buf, "modifiable", False) a3.call_function("setpos", ("'<", (buf.number, r1 + 1, c1 + 1, 0))) a3.call_function("setpos", ("'>", (buf.number, r2 + 1, c2 + 1, 0))) if new_row is not None: a3.win_set_cursor(win, (new_row, col)) try: (a1 + a2 + a3).commit(nvim) except NvimError as e: raise UnrecoverableError(e)
def _norm_mv(nvim: Nvim, up: bool) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, _ = win_get_cursor(nvim, win=win) lines = buf_line_count(nvim, buf=buf) if not writable(nvim, buf=buf): return else: if up: if row: nvim.command(f"move -2") else: if row < lines - 1: nvim.command(f"move +1")
def _go_replace_line(nvim: Nvim) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) if not writable(nvim, buf=buf): return else: linefeed = buf_linefeed(nvim, buf=buf) row, _ = win_get_cursor(nvim, win=win) body: str = nvim.funcs.getreg() new_lines = body.split(linefeed) if new_lines: n = new_lines.pop() if n: new_lines.append(n) buf_set_lines(nvim, buf=buf, lo=row, hi=row + 1, lines=new_lines)
def _toggle_case(nvim: Nvim) -> None: win = cur_win(nvim) row, col = win_get_cursor(nvim, win=win) buf = win_get_buf(nvim, win=win) if writable(nvim, buf=buf): line, *_ = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) bline = encode(line) before, after = bline[:col], bline[col:] if after: cur, *post = after pt = decode(bytes((cur, ))) swapped = _swap_case(pt) new = decode(before) + swapped + decode(bytes(post)) pos = len(before) + len(encode(swapped)) buf_set_lines(nvim, buf=buf, lo=row, hi=row + 1, lines=(new, )) win_set_cursor(nvim, win=win, row=row, col=pos)
def _toggle_case(nvim: Nvim) -> None: win = cur_win(nvim) row, col = win_get_cursor(nvim, win=win) buf = win_get_buf(nvim, win=win) if not writable(nvim, buf=buf): return else: line, *_ = buf_get_lines(nvim, buf=buf, lo=row, hi=row + 1) bline = line.encode() before, after = bline[:col], bline[col:] cur, *post = after pt = bytes((cur,)).decode() swapped = _swap_case(pt) new = before.decode() + swapped + bytes(post).decode() pos = len(before) + len(swapped.encode()) buf_set_lines(nvim, buf=buf, lo=row, hi=row + 1, lines=(new,)) win_set_cursor(nvim, win=win, row=row, col=pos)
def _indent(nvim: Nvim) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win) row, _ = win_get_cursor(nvim, win) tabsize: int = buf_get_option(nvim, buf=buf, key="tabstop") lines = buf_get_lines(nvim, buf=buf, lo=0, hi=-1) before, curr, after = lines[:row], lines[row], lines[row + 1:] init_lv = p_indent(curr, tabsize=tabsize) top = row - _p_inside(init_lv, tabsize=tabsize, lines=reversed(before)) btm = row + _p_inside(init_lv, tabsize=tabsize, lines=after) set_visual_selection(nvim, win=win, mode="V", mark1=(top, 0), mark2=(btm, 0))
def _set_trimmed(nvim: Nvim, win: Window, buf: Buffer) -> None: row, col = win_get_cursor(nvim, win=win) lines = buf_get_lines(nvim, buf=buf, lo=0, hi=-1) new_lines = [ decode(encode(line)[:col]) + decode(encode(line)[col:]).rstrip() if r == row else line.rstrip() for r, line in enumerate(lines) ] while new_lines: line = new_lines.pop() if line or len(new_lines) <= row: new_lines.append(line) break if len(new_lines) < len(lines): new_lines.append("") if new_lines != lines: buf_set_lines(nvim, buf=buf, lo=0, hi=-1, lines=new_lines) win_set_cursor(nvim, win=win, row=row, col=col)
def _indent(nvim: Nvim) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win) row, _ = win_get_cursor(nvim, win) tabsize: int = buf_get_option(nvim, buf=buf, key="tabstop") lines = buf_get_lines(nvim, buf=buf, lo=0, hi=-1) before, curr, after = lines[:row], lines[row], lines[row + 1:] init_lv = p_indent(curr, tabsize=tabsize) top = row - _p_inside(init_lv, tabsize=tabsize, lines=reversed(before)) btm = row + _p_inside(init_lv, tabsize=tabsize, lines=after) lines = deque(buf_get_lines(nvim, buf=buf, lo=top, hi=btm + 1)) while lines: if line := lines.popleft(): lines.appendleft(line) break else: top += 1
def _virt_text(nvim: Nvim, ghost: GhostText, text: str) -> None: if ghost.enabled: lhs, rhs = ghost.context overlay, *_ = text.splitlines() or ("", ) virt_text = lhs + overlay + rhs ns = create_ns(nvim, ns=_NS) win = cur_win(nvim) buf = win_get_buf(nvim, win=win) row, col = win_get_cursor(nvim, win=win) mark = ExtMark( idx=1, begin=(row, col), end=(row, col), meta={ "virt_text_pos": "overlay", "hl_mode": "combine", "virt_text": ((virt_text, ghost.highlight_group), ), }, ) clear_ns(nvim, buf=buf, id=ns) buf_set_extmarks(nvim, buf=buf, id=ns, marks=(mark, ))
def indices(nvim: Nvim, state: State, is_visual: bool) -> Iterator[Node]: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) if not is_fm_buffer(nvim, buf=buf): return None else: row, _ = win_get_cursor(nvim, win=win) node = _row_index(state, row) if node: yield node if is_visual: (row1, _), (row2, _) = operator_marks(nvim, buf=buf, visual_type=None) for r in range(row1, row2 + 1): if r != row: node = _row_index(state, r) if node: yield node
def redraw(nvim: Nvim, state: State, focus: Optional[str]) -> None: derived, current = state.derived, state.current focus_row = derived.path_row_lookup.get(focus) if focus else None current_row = derived.path_row_lookup.get(current or "") cwin = cur_win(nvim) ns = nvim.api.create_namespace(FM_NAMESPACE) for win, buf in find_fm_windows(nvim): p_count = buf_line_count(nvim, buf=buf) n_count = len(state.derived.lines) row, col = win_get_cursor(nvim, win=win) (r1, c1), (r2, c2) = operator_marks(nvim, buf=buf, visual_type=None) if focus_row is not None: new_row: Optional[int] = focus_row + 1 elif win != cwin and current_row is not None: new_row = current_row + 1 elif row >= n_count: new_row = n_count elif p_count != n_count: new_row = row + 1 else: new_row = None a1 = Atomic() a1.buf_set_option(buf, "modifiable", True) a2 = _update(nvim, buf=buf, ns=ns, derived=derived) a3 = Atomic() a3.buf_set_option(buf, "modifiable", False) a3.call_function("setpos", ("'<", (buf.number, r1 + 1, c1 + 1, 0))) a3.call_function("setpos", ("'>", (buf.number, r2 + 1, c2 + 1, 0))) if new_row is not None: a3.win_set_cursor(win, (new_row, col)) (a1 + a2 + a3).commit(nvim)
def _record_pos(nvim: Nvim) -> None: win = cur_win(nvim) buf = win_get_buf(nvim, win=win) _, col = win_get_cursor(nvim, win=win) buf_set_var(nvim, buf=buf, key=BUF_VAR_NAME, val=col)