|
- import re, os, vim, string, random
- from collections import deque, namedtuple
-
- _Placeholder = namedtuple("_FrozenPlaceholder", ["current_text", "start", "end"])
- _VisualContent = namedtuple("_VisualContent", ["mode", "text"])
- _Position = namedtuple("_Position", ["line", "col"])
-
-
- class _SnippetUtilCursor(object):
- def __init__(self, cursor):
- self._cursor = [cursor[0] - 1, cursor[1]]
- self._set = False
-
- def preserve(self):
- self._set = True
- self._cursor = [vim.buf.cursor[0], vim.buf.cursor[1]]
-
- def is_set(self):
- return self._set
-
- def set(self, line, column):
- self.__setitem__(0, line)
- self.__setitem__(1, column)
-
- def to_vim_cursor(self):
- return (self._cursor[0] + 1, self._cursor[1])
-
- def __getitem__(self, index):
- return self._cursor[index]
-
- def __setitem__(self, index, value):
- self._set = True
- self._cursor[index] = value
-
- def __len__(self):
- return 2
-
- def __str__(self):
- return str((self._cursor[0], self._cursor[1]))
-
-
- class IndentUtil(object):
-
- """Utility class for dealing properly with indentation."""
-
- def __init__(self):
- self.reset()
-
- def reset(self):
- """Gets the spacing properties from Vim."""
- self.shiftwidth = int(
- vim.eval("exists('*shiftwidth') ? shiftwidth() : &shiftwidth")
- )
- self._expandtab = vim.eval("&expandtab") == "1"
- self._tabstop = int(vim.eval("&tabstop"))
-
- def ntabs_to_proper_indent(self, ntabs):
- """Convert 'ntabs' number of tabs to the proper indent prefix."""
- line_ind = ntabs * self.shiftwidth * " "
- line_ind = self.indent_to_spaces(line_ind)
- line_ind = self.spaces_to_indent(line_ind)
- return line_ind
-
- def indent_to_spaces(self, indent):
- """Converts indentation to spaces respecting Vim settings."""
- indent = indent.expandtabs(self._tabstop)
- right = (len(indent) - len(indent.rstrip(" "))) * " "
- indent = indent.replace(" ", "")
- indent = indent.replace("\t", " " * self._tabstop)
- return indent + right
-
- def spaces_to_indent(self, indent):
- """Converts spaces to proper indentation respecting Vim settings."""
- if not self._expandtab:
- indent = indent.replace(" " * self._tabstop, "\t")
- return indent
-
-
- class SnippetUtil(object):
-
- """Provides easy access to indentation, etc.
-
- This is the 'snip' object in python code.
-
- """
-
- def __init__(self, _initial_indent, start, end, context):
- self._ind = IndentUtil()
- self._visual = _VisualContent(
- vim.eval("visualmode()"), vim.eval('get(g:,"coc_selected_text","")')
- )
- self._initial_indent = _initial_indent
- self._reset("")
- self._start = start
- self._end = end
- self._context = context
-
- def _reset(self, cur):
- """Gets the snippet ready for another update.
-
- :cur: the new value for c.
-
- """
- self._ind.reset()
- self._cur = cur
- self._rv = ""
- self._changed = False
- self.reset_indent()
-
- def shift(self, amount=1):
- """Shifts the indentation level. Note that this uses the shiftwidth
- because thats what code formatters use.
-
- :amount: the amount by which to shift.
-
- """
- self.indent += " " * self._ind.shiftwidth * amount
-
- def unshift(self, amount=1):
- """Unshift the indentation level. Note that this uses the shiftwidth
- because thats what code formatters use.
-
- :amount: the amount by which to unshift.
-
- """
- by = -self._ind.shiftwidth * amount
- try:
- self.indent = self.indent[:by]
- except IndexError:
- self.indent = ""
-
- def mkline(self, line="", indent=""):
- """Creates a properly set up line.
-
- :line: the text to add
- :indent: the indentation to have at the beginning
- if None, it uses the default amount
-
- """
- return indent + line
-
- def reset_indent(self):
- """Clears the indentation."""
- self.indent = self._initial_indent
-
- # Utility methods
- @property
- def fn(self): # pylint:disable=no-self-use,invalid-name
- """The filename."""
- return vim.eval('expand("%:t")') or ""
-
- @property
- def basename(self): # pylint:disable=no-self-use
- """The filename without extension."""
- return vim.eval('expand("%:t:r")') or ""
-
- @property
- def ft(self): # pylint:disable=invalid-name
- """The filetype."""
- return self.opt("&filetype", "")
-
- @property
- def rv(self): # pylint:disable=invalid-name
- """The return value.
-
- The text to insert at the location of the placeholder.
-
- """
- return self._rv
-
- @rv.setter
- def rv(self, value): # pylint:disable=invalid-name
- """See getter."""
- self._changed = True
- self._rv = value
-
- @property
- def _rv_changed(self):
- """True if rv has changed."""
- return self._changed
-
- @property
- def c(self): # pylint:disable=invalid-name
- """The current text of the placeholder."""
- return ""
-
- @property
- def v(self): # pylint:disable=invalid-name
- """Content of visual expansions."""
- return self._visual
-
- @property
- def p(self):
- if "coc_last_placeholder" in vim.vars:
- p = vim.vars["coc_last_placeholder"]
- start = _Position(p["start"]["line"], p["start"]["col"])
- end = _Position(p["end"]["line"], p["end"]["col"])
- return _Placeholder(p["current_text"], start, end)
- return None
-
- @property
- def context(self):
- return self._context
-
- def opt(self, option, default=None): # pylint:disable=no-self-use
- """Gets a Vim variable."""
- if vim.eval("exists('%s')" % option) == "1":
- try:
- return vim.eval(option)
- except vim.error:
- pass
- return default
-
- def __add__(self, value):
- """Appends the given line to rv using mkline."""
- self.rv += "\n" # pylint:disable=invalid-name
- self.rv += self.mkline(value)
- return self
-
- def __lshift__(self, other):
- """Same as unshift."""
- self.unshift(other)
-
- def __rshift__(self, other):
- """Same as shift."""
- self.shift(other)
-
- @property
- def snippet_start(self):
- """
- Returns start of the snippet in format (line, column).
- """
- return self._start
-
- @property
- def snippet_end(self):
- """
- Returns end of the snippet in format (line, column).
- """
- return self._end
-
- @property
- def buffer(self):
- return vim.buf
-
-
- class ContextSnippet(object):
- def __init__(self):
- self.buffer = vim.current.buffer
- self.window = vim.current.window
- self.cursor = _SnippetUtilCursor(vim.current.window.cursor)
- self.line = vim.call("line", ".") - 1
- self.column = vim.call("col", ".") - 1
- line = vim.call("getline", ".")
- self.after = line[self.column :]
- if "coc_selected_text" in vim.vars:
- self.visual_mode = vim.eval("visualmode()")
- self.visual_text = vim.vars["coc_selected_text"]
- else:
- self.visual_mode = None
- self.visual_text = ""
- if "coc_last_placeholder" in vim.vars:
- p = vim.vars["coc_last_placeholder"]
- start = _Position(p["start"]["line"], p["start"]["col"])
- end = _Position(p["end"]["line"], p["end"]["col"])
- self.last_placeholder = _Placeholder(p["current_text"], start, end)
- else:
- self.last_placeholder = None
|