예제 #1
0
  def run(self, edit):
    v = self.view
    if v.sel()[0].size() == 0:
        v.run_command("expand_selection", {"to": "word"})

    cur_start = v.sel()[0].begin()
    cur_end = v.sel()[0].end()

    for sel in v.sel():
        text = v.substr(sel)
        res = self.matcher(text)
        
        if not res:
          #first check one character to the left to see if its a symbol
          sel = Region(sel.begin() - 1, sel.end())
          text = v.substr(sel)
          res = self.matcher(text)

          if not res:
            #now expand selection one character to the right to see if its a string
            sel = Region(sel.begin(), sel.end() + 1)
            text = v.substr(sel)
            res = self.matcher(text)

            if not res:
              #this is a mute point
              continue

        self.replacer(v, edit, sel, text, res)

    v.sel().clear()
    v.sel().add(Region(cur_start, cur_end))
예제 #2
0
    def run(self, edit):
        v = self.view
        if v.sel()[0].size() == 0:
            v.run_command("expand_selection", {"to": "word"})

        cur_start = v.sel()[0].begin()
        cur_end = v.sel()[0].end()

        for sel in v.sel():
            text = v.substr(sel)
            res = self.matcher(text)

            if not res:
                #first check one character to the left to see if its a symbol
                sel = Region(sel.begin() - 1, sel.end())
                text = v.substr(sel)
                res = self.matcher(text)

                if not res:
                    #now expand selection one character to the right to see if its a string
                    sel = Region(sel.begin(), sel.end() + 1)
                    text = v.substr(sel)
                    res = self.matcher(text)

                    if not res:
                        #this is a mute point
                        continue

            self.replacer(v, edit, sel, text, res)

        v.sel().clear()
        v.sel().add(Region(cur_start, cur_end))
예제 #3
0
def find_sentences_backward(view, start_pt: int, count: int = 1) -> Region:
    if isinstance(start_pt, Region):
        start_pt = start_pt.a

    pt = prev_non_ws(view, start_pt)
    sen = Region(pt)
    prev = sen
    while True:
        sen = view.expand_by_class(sen, CLASS_LINE_END | CLASS_PUNCTUATION_END)
        if sen.a <= 0 or view.substr(sen.begin() - 1) in ('.', '\n', '?', '!'):
            if view.substr(sen.begin() - 1) == '.' and not view.substr(sen.begin()) == ' ':
                continue

            if prev == sen:
                break

            prev = sen

            if sen:
                pt = next_non_blank(view, sen.a)
                if pt < sen.b and pt != start_pt:
                    if view.substr(pt) == '\n':
                        if pt + 1 != start_pt:
                            pt += 1

                    return Region(pt)

                if pt > 0:
                    continue

            return sen

    return sen
예제 #4
0
def remove_comments(view: sublime.View, edit: sublime.Edit,
                    region: sublime.Region, tokens: dict):
    "Removes comment markers from given region. Returns amount of characters removed"
    text = view.substr(region)

    if text.startswith(tokens['start']) and text.endswith(tokens['end']):
        start_offset = region.begin() + len(tokens['start'])
        end_offset = region.end() - len(tokens['end'])

        # Narrow down offsets for whitespace
        if view.substr(start_offset).isspace():
            start_offset += 1

        if view.substr(end_offset - 1).isspace():
            end_offset -= 1

        start_region = sublime.Region(region.begin(), start_offset)
        end_region = sublime.Region(end_offset, region.end())

        # It's faster to erase the start region first
        # See comment in Default/comment.py plugin
        view.erase(edit, start_region)

        end_region = sublime.Region(end_region.begin() - start_region.size(),
                                    end_region.end() - start_region.size())

        view.erase(edit, end_region)
        return start_region.size() + end_region.size()

    return 0
예제 #5
0
def get_line_indent(view: sublime.View, line: sublime.Region) -> str:
    "Returns indentation for given line"
    pos = line.begin()
    end = line.end()
    while pos < end and view.substr(pos).isspace():
        pos += 1

    return view.substr(sublime.Region(line.begin(), pos))
예제 #6
0
def replace_with_snippet(view: sublime.View, edit: sublime.Edit,
                         region: sublime.Region, snippet: str):
    "Replaces given region view with snippet contents"
    sel = view.sel()
    sel.clear()
    sel.add(sublime.Region(region.begin(), region.begin()))
    view.replace(edit, region, '')
    view.run_command('insert_snippet', {'contents': snippet})
예제 #7
0
def get_line_indent(view: sublime.View, line: sublime.Region) -> str:
    "Returns indentation for given line or line found from given character location"
    if isinstance(line, int):
        line = view.line(line)
    pos = line.begin()
    end = line.end()
    while pos < end and view.substr(pos).isspace():
        pos += 1

    return view.substr(sublime.Region(line.begin(), pos))
예제 #8
0
def find_sentences_backward(view, start_pt, count=1):
    if isinstance(start_pt, Region):
        start_pt = start_pt.a

    pt = utils.previous_non_white_space_char(view, start_pt, white_space='\n \t')
    sen = Region(pt)
    while True:
        sen = view.expand_by_class(sen, CLASS_LINE_END | CLASS_PUNCTUATION_END)
        if sen.a <= 0 or view.substr(sen.begin() - 1) in ('.', '\n', '?', '!'):
            if view.substr(sen.begin() - 1) == '.' and not view.substr(sen.begin()) == ' ':
                continue

            return sen
def update_region(region: sublime.Region, delta: int,
                  last_pos: int) -> sublime.Region:
    if delta < 0:
        # Content removed
        if last_pos == region.begin():
            # Updated content at the abbreviation edge
            region.a += delta
            region.b += delta
        elif region.begin() < last_pos <= region.end():
            region.b += delta
    elif delta > 0 and region.begin() <= last_pos <= region.end():
        # Content inserted
        region.b += delta

    return region
    def run(self, edit):
        v = self.view
        if v.sel()[0].size() == 0:
            v.run_command("expand_selection", {"to": "scope"})

        for sel in v.sel():
            text = v.substr(sel)
            res = re_quotes.match(text)
            if not res:
                #  the current selection doesn't begin and end with a quote.
                #  let's expand the selection one character each direction and try again
                sel = Region(sel.begin() - 1, sel.end() + 1)
                text = v.substr(sel)
                res = re_quotes.match(text)
                if not res:
                    #  still no match... skip it!
                    continue
            prevSpace = res.group(1)
            oldQuotes = res.group(2)
            newQuotes = "'" if oldQuotes == '"' else '"'
            text = res.group(3)
            text = string.replace(text, newQuotes, "\\" + newQuotes)
            text = string.replace(text, "\\" + oldQuotes, oldQuotes)
            text = prevSpace + newQuotes + text + newQuotes
            v.replace(edit, sel, text)
    def run(self, edit, **kwargs):
        v = self.view
        if v.sel()[0].size() == 0:
            v.run_command('expand_selection', {'to': 'scope'})

        for sel in v.sel():
            text = v.substr(sel)
            res = re_quotes.match(text)
            if not res:
                #  the current selection doesn't begin and end with a quote.
                #  let's expand the selection one character each direction and try again
                sel = Region(sel.begin() - 1, sel.end() + 1)
                text = v.substr(sel)
                res = re_quotes.match(text)
                if not res:
                    #  still no match... skip it!
                    continue
            oldQuotes = res.group(1)
            if 'key' in kwargs:
                newQuotes = kwargs['key']
            else:
                newQuotes = quoteList[(quoteList.index(oldQuotes) + 1) % len(quoteList)]
            text = res.group(2)
            text = text.replace(newQuotes, "\\" + newQuotes)
            text = text.replace("\\" + oldQuotes, oldQuotes)
            text = newQuotes + text + newQuotes
            v.replace(edit, sel, text)
예제 #12
0
def _get_text_object_bracket(view, s: Region, inclusive: bool, count: int, delims: tuple) -> Region:
    opening = find_prev_lone_bracket(view, max(0, s.begin() - 1), delims)
    closing = find_next_lone_bracket(view, s.end(), delims)

    if not (opening and closing):
        return s

    if inclusive:
        return Region(opening.a, closing.b)

    a = opening.a + 1
    if view.substr(a) == '\n':
        a += 1

    b = closing.b - 1

    if b > a:
        line = view.line(b)

        if next_non_blank(view, line.a) + 1 == line.b:
            row_a, col_a = view.rowcol(a - 1)
            row_b, col_b = view.rowcol(b + 1)
            if (row_b - 1) > row_a:
                line = view.full_line(view.text_point((row_b - 1), 0))

                return Region(a, line.b)

    return Region(a, b)
def get_wrap_region(view: sublime.View, sel: sublime.Region,
                    config: Config) -> sublime.Region:
    "Returns region to wrap with abbreviation"
    if sel.empty():
        # No selection means user wants to wrap current tag container
        pt = sel.begin()
        ctx = emmet.get_tag_context(view, pt)
        if ctx:
            # Check how given point relates to matched tag:
            # if it's in either open or close tag, we should wrap tag itself,
            # otherwise we should wrap its contents
            open_tag = ctx.get('open')
            close_tag = ctx.get('close')

            if in_range(open_tag, pt) or (close_tag
                                          and in_range(close_tag, pt)):
                return sublime.Region(
                    open_tag.begin(), close_tag and close_tag.end()
                    or open_tag.end())

            if close_tag:
                r = sublime.Region(open_tag.end(), close_tag.begin())
                return utils.narrow_to_non_space(view, r)

    return utils.narrow_to_non_space(view, sel)
예제 #14
0
def get_block(view: sublime.View, s: sublime.Region) -> (str, sublime.Region):
    """Get the code block under the cursor.

    The code block is the lines satisfying the following conditions:

      - Includes the line under the cursor.
      - Includes no blank line.
      - More indented than that of the line under the cursor.

    If `s` is a selected region, the code block is it.
    """
    if not s.empty():
        return (view.substr(s), s)
    view_end_row = view.rowcol(view.size())[0]
    current_row = view.rowcol(s.begin())[0]
    current_indent = get_indent(view, current_row)
    start_point = 0
    for first_row in range(current_row, -1, -1):
        indent = get_indent(view, first_row)
        if (not indent.startswith(current_indent)
                or get_line(view, first_row).strip() == ''):
            start_point = view.text_point(first_row + 1, 0)
            break
    end_point = view.size()
    for last_row in range(current_row, view_end_row + 1):
        indent = get_indent(view, last_row)
        if (not indent.startswith(current_indent)
                or get_line(view, last_row).strip() == ''):
            end_point = view.text_point(last_row, 0) - 1
            break
    block_region = sublime.Region(start_point, end_point)
    return (view.substr(block_region), block_region)
예제 #15
0
def select_item(view: sublime.View,
                sel: sublime.Region,
                is_css=False,
                is_previous=False):
    "Selects next/previous item for CSS source"
    buffer_id = view.buffer_id()
    pos = sel.begin()

    # Check if we are still in calculated model
    model = models_for_buffer.get(buffer_id)
    if model:
        region = find_region(sel, model.ranges, is_previous)
        if region:
            select(view, region)
            return

        # Out of available selection range, move to next tag
        pos = model.start if is_previous else model.end

    # Calculate new model from current editor content
    content = utils.get_content(view)
    model = emmet.select_item(content, pos, is_css, is_previous)
    if model:
        models_for_buffer[buffer_id] = model
        region = find_region(sel, model.ranges, is_previous)
        if region:
            select(view, region)
            return
예제 #16
0
def is_valid_tracker(tracker: AbbreviationTracker, region: sublime.Region,
                     pos: int) -> bool:
    "Check if given tracker is in valid state for keeping it marked"
    if isinstance(tracker, AbbreviationTrackerError):
        if region.end() == pos:
            # Last entered character is invalid
            return False

        abbreviation = tracker.abbreviation
        start = region.begin()
        target_pos = region.end()

        if '</' in abbreviation:
            # XXX Silly check for auto-consed tag in JSX (see Naomi syntax)
            # Find better solution
            return False

        if syntax.is_jsx(tracker.config.syntax):
            start += 1

        while target_pos > start:
            ch = abbreviation[target_pos - start - 1]
            if ch in pairs_end:
                target_pos -= 1
            else:
                break

        return target_pos != pos

    return True
예제 #17
0
def get_wrap_region(view: sublime.View, sel: sublime.Region,
                    config: Config) -> sublime.Region:
    "Returns region to wrap with abbreviation"
    if sel.empty():
        # No selection means user wants to wrap current tag container
        pt = sel.begin()
        ctx = emmet.get_tag_context(view, pt)
        if ctx:
            # Check how given point relates to matched tag:
            # if it's in either open or close tag, we should wrap tag itself,
            # otherwise we should wrap its contents
            open_tag = ctx.get('open')
            close_tag = ctx.get('close')

            if in_range(open_tag, pt) or (close_tag
                                          and in_range(close_tag, pt)):
                return sublime.Region(
                    open_tag.begin(), close_tag and close_tag.end()
                    or open_tag.end())

            if close_tag:
                r = sublime.Region(open_tag.end(), close_tag.begin())
                next_region = utils.narrow_to_non_space(view, r)

                # On the right side of tag contents, we should skip new lines only
                # and trim spaces at the end of line
                padding = view.substr(
                    sublime.Region(next_region.end(), r.end()))
                ix = padding.find('\n')
                end = next_region.end() + ix if ix != -1 else r.end()
                next_region = sublime.Region(next_region.begin(), end)

                return next_region

    return utils.narrow_to_non_space(view, sel, utils.NON_SPACE_LEFT)
예제 #18
0
def _get_text_object_tag(view, s: Region, inclusive: bool, count: int) -> Region:
    # When the active cursor position is on leading whitespace before a tag on
    # the same line then the start point of the text object is the tag.
    line = view.line(get_insertion_point_at_b(s))
    tag_in_line = view_find_in_range(view, '^\\s*<[^>]+>', line.begin(), line.end())
    if tag_in_line:
        if s.b >= s.a and s.b < tag_in_line.end():
            if s.empty():
                s.a = s.b = tag_in_line.end()
            else:
                s.a = tag_in_line.end()
                s.b = tag_in_line.end() + 1

    begin_tag, end_tag, _ = find_containing_tag(view, s.begin())
    if not (begin_tag and end_tag):
        return s

    # The normal method is to select a <tag> until the matching </tag>. For "at"
    # the tags are included, for "it" they are excluded. But when "it" is
    # repeated the tags will be included (otherwise nothing would change).
    if not inclusive:
        if s == Region(begin_tag.end(), end_tag.begin()):
            inclusive = True

    if inclusive:
        return Region(begin_tag.a, end_tag.b)
    else:
        return Region(begin_tag.b, end_tag.a)
예제 #19
0
def new_char_phantom(view: sublime.View,
                     char_region: sublime.Region) -> sublime.Phantom:
    char = view.substr(char_region)[0]

    return sublime.Phantom(
        # the "begin" position has a better visual selection result than the "end" position
        sublime.Region(char_region.begin()),
        generate_phantom_html(view, char),
        layout=sublime.LAYOUT_INLINE,
    )
예제 #20
0
def get_cell(view: sublime.View,
             region: sublime.Region,
             *,
             logger=HERMES_LOGGER) -> (str, sublime.Region):
    """Get the code cell under the cursor.

    Cells are separated by markers defined in `cell_delimiter_pattern` in the config file.

    If `s` is a selected region, the code cell is it.
    """
    if not region.empty():
        return (view.substr(region), region)
    cell_delimiter_pattern = (sublime.load_settings(
        "Hermes.sublime-settings").get("cell_delimiter_pattern"))
    separators = view.find_all(cell_delimiter_pattern)
    r = sublime.Region(region.begin() + 1, region.begin() + 1)
    start_point = separators[bisect.bisect(separators, r) - 1].end() + 1
    end_point = separators[bisect.bisect(separators, r)].begin() - 1
    cell_region = sublime.Region(start_point, end_point)
    return (view.substr(cell_region), cell_region)
예제 #21
0
    def run(self, edit):
        sel = self.view.sel()
        current = sel[0].begin()
        line = self.view.line(current)
        length = line.end() - line.begin()

        upper = '/*==' + ('-' * (length - 1))
        bottom = '/' + ('-' * (length - 1)) + '==*/'

        added = self.view.insert(edit, line.begin(), upper + '\n/ ')
        line = Region(line.begin() + added, line.end() + added)
        self.view.insert(edit, line.end(), '\n' + bottom)
예제 #22
0
def is_regions_intersected(region_1: sublime.Region, region_2: sublime.Region, allow_boundary: bool = False) -> bool:
    """
    @brief Check whether two regions are intersected.

    @param region_1       The 1st region
    @param region_2       The 2nd region
    @param allow_boundary Treat boundary contact as intersected

    @return True if intersected, False otherwise.
    """

    # treat boundary contact as intersected
    if allow_boundary:
        # left/right begin/end = l/r b/e
        lb_, le_ = region_1.begin(), region_1.end()
        rb_, re_ = region_2.begin(), region_2.end()

        if lb_ == rb_ or lb_ == re_ or le_ == rb_ or le_ == re_:
            return True

    return region_1.intersects(region_2)
예제 #23
0
파일: paredit.py 프로젝트: eerohele/Tutkain
def wrap_bracket(view, edit, open_bracket):
    close_bracket = sexp.OPEN[open_bracket]

    for region, sel in iterate(view):
        if not region.empty():
            view.insert(edit, region.end(), close_bracket)
            view.insert(edit, region.begin(), open_bracket)
        else:
            point = region.begin()
            form = forms.find_adjacent(view, point)

            # cursor is in between the dispatch macro and an open paren
            if (form and view.match_selector(point - 1,
                                             "keyword.operator.macro")
                    and view.match_selector(point, selectors.SEXP_BEGIN)):
                form = Region(form.begin() + 1, form.end())

            if not form:
                form = Region(point, point)
                sel.append(Region(point + 1, point + 1))

            view.insert(edit, form.end(), close_bracket)
            view.insert(edit, form.begin(), open_bracket)
예제 #24
0
def get_content(view: sublime.View, region: sublime.Region, lines=False):
    "Returns contents of given region, properly de-indented"
    base_line = view.substr(view.line(region.begin()))
    m = re_indent.match(base_line)
    indent = m.group(0) if m else ''
    src_lines = view.substr(region).splitlines()
    dest_lines = []

    for line in src_lines:
        if dest_lines and line.startswith(indent):
            line = line[len(indent):]
        dest_lines.append(line)

    return dest_lines if lines else '\n'.join(dest_lines)
예제 #25
0
def narrow_to_non_space(view: sublime.View,
                        region: sublime.Region) -> sublime.Region:
    "Returns copy of region which starts and ends at non-space character"
    begin = region.begin()
    end = region.end()

    while begin < end:
        if not view.substr(begin).isspace():
            break
        begin += 1

    while end > begin:
        if not view.substr(end - 1).isspace():
            break
        end -= 1

    return sublime.Region(begin, end)
예제 #26
0
파일: indent.py 프로젝트: eerohele/Tutkain
def indent_region(view, edit, region, prune=False):
    if region and not view.match_selector(region.begin(), IGNORE_SELECTORS):
        new_lines = []

        for line in view.lines(region):
            replacee = line

            if new_lines:
                if previous := new_lines.pop():
                    begin = previous.end()
                    end = begin + line.size()
                    replacee = Region(begin, end)

            if replacer := get_indented_string(view, replacee, prune=prune):
                view.replace(edit, replacee, replacer)
                new_lines.append(view.full_line(replacee.begin()))
                restore_cursors(view)
def convert_from_data_url(view: sublime.View, region: sublime.Region, dest: str):
    src = view.substr(region)
    m = re.match(r'^data\:.+?;base64,(.+)', src)
    if m:
        base_dir = os.path.dirname(view.file_name())
        abs_dest = utils.create_path(base_dir, dest)
        file_url = os.path.relpath(abs_dest, base_dir).replace('\\', '/')

        dest_dir = os.path.dirname(abs_dest)
        if not os.path.exists(dest_dir):
            os.makedirs(dest_dir)

        with open(abs_dest, 'wb') as fd:
            fd.write(base64.urlsafe_b64decode(m.group(1)))

        view.run_command('convert_data_url_replace', {
            'region': [region.begin(), region.end()],
            'text': file_url
        })
예제 #28
0
def narrow_to_non_space(
        view: sublime.View,
        region: sublime.Region,
        direction=NON_SPACE_LEFT | NON_SPACE_RIGHT) -> sublime.Region:
    "Returns copy of region which starts and ends at non-space character"
    begin = region.begin()
    end = region.end()

    if direction & NON_SPACE_LEFT:
        while begin < end:
            if not view.substr(begin).isspace():
                break
            begin += 1

    if (direction & NON_SPACE_RIGHT):
        while end > begin:
            if not view.substr(end - 1).isspace():
                break
            end -= 1

    return sublime.Region(begin, end)
예제 #29
0
def get_comment_regions(view: sublime.View, region: sublime.Region, tokens: dict):
    "Finds comments inside given region and returns their regions"
    result = []
    text = view.substr(region)
    start = region.begin()
    offset = 0

    while True:
        c_start = text.find(tokens['start'], offset)
        if c_start != -1:
            offset = c_start + len(tokens['start'])

            # Find comment end
            c_end = text.find(tokens['end'], offset)
            if c_end != -1:
                offset = c_end + len(tokens['end'])
                result.append(sublime.Region(start + c_start, start + offset))
        else:
            break

    return result
def get_wrap_region(view: sublime.View, sel: sublime.Region,
                    options: dict) -> sublime.Region:
    "Returns region to wrap with abbreviation"
    if sel.empty() and options.get('context'):
        # If there’s no selection than user wants to wrap current tag container
        ctx = options['context']
        pt = sel.begin()

        # Check how given point relates to matched tag:
        # if it's in either open or close tag, we should wrap tag itself,
        # otherwise we should wrap its contents
        open_tag = ctx.get('open')
        close_tag = ctx.get('close')

        if in_range(open_tag, pt) or (close_tag and in_range(close_tag, pt)):
            return sublime.Region(
                open_tag.begin(), close_tag and close_tag.end()
                or open_tag.end())

        if close_tag:
            r = sublime.Region(open_tag.end(), close_tag.begin())
            return utils.narrow_to_non_space(view, r)

    return sel
예제 #31
0
    def run(self, edit):
        v = self.view
        if v.sel()[0].size() == 0:
            v.run_command("expand_selection", {"to": "scope"})

        for sel in v.sel():
            text = v.substr(sel)
            res = re_quotes.match(text)
            if not res:
                #  the current selection doesn't begin and end with a quote.
                #  let's expand the selection one character each direction and try again
                sel = Region(sel.begin() - 1, sel.end() + 1)
                text = v.substr(sel)
                res = re_quotes.match(text)
                if not res:
                    #  still no match... skip it!
                    continue
            oldQuotes = res.group(1)
            newQuotes = "'" if oldQuotes == '"' else '"'
            text = res.group(2)
            text = string.replace(text, newQuotes, "\\" + newQuotes)
            text = string.replace(text, "\\" + oldQuotes, oldQuotes)
            text = newQuotes + text + newQuotes
            v.replace(edit, sel, text)
예제 #32
0
    def _f(view, s):
        if mode == INTERNAL_NORMAL:
            if len(target) != 1:
                return s

            # The *target* letters w, W, s, and p correspond to a |word|, a
            # |WORD|, a |sentence|, and a |paragraph| respectively.  These are
            # special in that they have nothing to delete, and used with |ds| they
            # are a no-op. With |cs|, one could consider them a slight shortcut for
            # ysi (cswb == ysiwb, more or less).

            noop = 'wWsp'
            if target in noop:
                return s

            valid_targets = '\'"`b()B{}r[]a<>t.,-_;:@#~*\\/'
            if target not in valid_targets:
                return s

            # All marks, except punctuation marks, are only searched for on the
            # current line.

            # If opening punctuation mark is used, contained whitespace is also trimmed.
            trim_contained_whitespace = True if target in '({[<' else False
            search_current_line_only = False if target in 'b()B{}r[]a<>' else True

            # Expand targets into begin and end variables because punctuation marks
            # and their aliases represent themselves and their counterparts e.g. (),
            # []. Target is the same for begin and end for all other valid marks
            # e.g. ', ", `, -, _, etc.

            t_char_begin, t_char_end = _get_punctuation_marks(target)

            s_rowcol_begin = view.rowcol(s.begin())
            s_rowcol_end = view.rowcol(s.end())

            # A t is a pair of HTML or XML tags.
            if target == 't':
                # TODO test dst works when cursor position is inside tag begin <a|bc>x</abc> -> dst -> |x
                # TODO test dst works when cursor position is inside tag end   <abc>x</a|bc> -> dst -> |x
                t_region_end = view.find('<\\/.*?>', s.b)
                t_region_begin = reverse_search(view,
                                                '<.*?>',
                                                start=0,
                                                end=s.b)
            else:
                current = view.substr(s.begin())
                # TODO test ds{char} works when cursor position is on target begin |"x" -> ds" -> |x
                # TODO test ds{char} works when cursor position is on target end   "x|" -> ds" -> |x
                if current == t_char_begin:
                    t_region_begin = Region(s.begin(), s.begin() + 1)
                else:
                    t_region_begin = _rfind(view,
                                            t_char_begin,
                                            start=0,
                                            end=s.begin(),
                                            flags=LITERAL)

                t_region_begin_rowcol = view.rowcol(t_region_begin.begin())

                t_region_end = _find(view,
                                     t_char_end,
                                     start=t_region_begin.end(),
                                     flags=LITERAL)
                t_region_end_rowcol = view.rowcol(t_region_end.end())

                if search_current_line_only:
                    if t_region_begin_rowcol[0] != s_rowcol_begin[0]:
                        return s

                    if t_region_end_rowcol[0] != s_rowcol_end[0]:
                        return s

                if trim_contained_whitespace:
                    t_region_begin_ws = _find(view,
                                              '\\s*.',
                                              start=t_region_begin.end())
                    t_region_end_ws = _rfind(view,
                                             '.\\s*',
                                             start=t_region_begin.end(),
                                             end=t_region_end.begin())

                    if t_region_begin_ws.size() > 1:
                        t_region_begin = Region(t_region_begin.begin(),
                                                t_region_begin_ws.end() - 1)

                    if t_region_end_ws.size() > 1:
                        t_region_end = Region(t_region_end_ws.begin() + 1,
                                              t_region_end.end())

            # Note: Be careful using boolean evaluation on a Region because an empty
            # Region evaluates to False. It evaluates to False because Region
            # invokes `__len__()` which will be zero if the Region is empty e.g.
            # `Region(3).size()` is `0`, whereas `Region(3, 4).size()` is `1`.
            # `sublime.View.find(sub)` returns `Region(-1)` if *sub* not found. This
            # is similar to how the python `str.find(sub)` function works i.e. it
            # returns `-1` if *sub* not found, because *sub* could be found at
            # position `0`. To check if a Region was found use `Region(3) >= 0`. To
            # check if a Region is non empty you can use boolean evaluation i.e. `if
            # Region(3): ...`. In the following case boolean evaluation is
            # intentional.

            if not (t_region_end and t_region_begin):
                return s

            # It's important that the end is replaced first. If we replaced the
            # begin region first then the end replacement would be off-by-one
            # because the begin is reducing the size of the internal buffer by one
            # i.e. it's deleting a character.

            view.replace(edit, t_region_end, '')
            view.replace(edit, t_region_begin, '')

            return Region(t_region_begin.begin())

        return s
예제 #33
0
 def key_function(self, region: sublime.Region) -> Callable[[int], int]:
     return lambda i: -abs(self.matches[i][0] - region.begin())
예제 #34
0
    def run_each(self, edit, region, braces="{}", pressed=None, unindent=False, select=False, replace=False):
        """
        Options:
            braces    a list of matching braces or a string containing the pair
            pressed   the key pressed; used for closing vs opening logic
            unindent  removes one "tab" from a newline.  true for braces that handle indent, like {}
            select    whether to select the region inside the braces
            replace   whether to insert new braces where the old braces were
        """
        if self.view.settings().get("translate_tabs_to_spaces"):
            tab = " " * self.view.settings().get("tab_size")
        else:
            tab = "\t"

        row, col = self.view.rowcol(region.begin())
        indent_point = self.view.text_point(row, 0)
        if indent_point < region.begin():
            indent = self.view.substr(Region(indent_point, region.begin()))
            indent = re.match("[ \t]*", indent).group(0)
        else:
            indent = ""
        line = self.view.substr(self.view.line(region.a))
        selection = self.view.substr(region)

        # for braces that have newlines ("""), insert the current line's indent
        if isinstance(braces, list):
            l_brace = braces[0]
            r_brace = braces[1]
            braces = "".join(braces)
            braces = braces.replace("\n", "\n" + indent)
            length = len(l_brace)
        else:
            braces = braces.replace("\n", "\n" + indent)
            length = len(braces) // 2
            l_brace = braces[:length]
            r_brace = braces[length:]

        if region.empty():
            after = self.view.substr(Region(region.a, region.a + length))

            insert_braces = braces
            complicated_check = self.complicated_quote_checker(insert_braces, region, pressed, after, r_brace)

            if complicated_check:
                insert_braces = complicated_check
            elif (
                pressed and after == r_brace and r_brace[-1] == pressed
            ):  # and (pressed not in QUOTING_BRACKETS or in_string_scope):
                # in this case we pressed the closing character, and that's the character that is to the right
                # so do nothing except advance cursor position
                insert_braces = False
            elif unindent and row > 0 and indent and line == indent:
                # indent has the current line's indent
                # get previous line's indent:
                prev_point = self.view.text_point(row - 1, 0)
                prev_line = self.view.line(prev_point)
                prev_indent = self.view.substr(prev_line)
                prev_indent = re.match("[ \t]*", prev_indent).group(0)

                if (
                    (not pressed or pressed == l_brace)
                    and len(indent) > len(prev_indent)
                    and indent[len(prev_indent) :] == tab
                ):
                    # move region.a back by 'indent' amount
                    region = Region(region.a - len(tab), region.b - len(tab))
                    # and remove the tab
                    self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), "")
                elif pressed and pressed == r_brace:
                    if len(indent) == len(prev_indent):
                        # move region.a back by 'indent' amount
                        region = Region(region.a - len(tab), region.b - len(tab))
                        # and remove the tab
                        self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), "")
                    insert_braces = r_brace
            elif pressed and pressed != l_brace:
                # we pressed the closing bracket or quote.  This *never*
                insert_braces = r_brace

            if insert_braces:
                self.view.insert(edit, region.a, insert_braces)
            self.view.sel().add(Region(region.a + length, region.a + length))
        elif selection in QUOTING_BRACKETS and pressed in QUOTING_BRACKETS and selection != pressed:
            # changing a quote from single <=> double, just insert the quote.
            self.view.replace(edit, region, pressed)
            self.view.sel().add(Region(region.end(), region.end()))
        elif pressed and pressed != l_brace:
            b = region.begin() + len(r_brace)
            self.view.replace(edit, region, r_brace)
            self.view.sel().add(Region(b, b))
        else:
            substitute = self.view.substr(region)
            replacement = l_brace + substitute + r_brace
            # if we're inserting "real" brackets, not quotes:
            real_brackets = l_brace in OPENING_BRACKETS and r_brace in CLOSING_BRACKETS

            # check to see if entire lines are selected, and if so do some smart indenting
            # bol_is_nl => allman style {}
            # bol_at_nl => kernigan&ritchie
            if region.begin() == 0:
                bol_is_nl = True
                bol_at_nl = False
            elif len(self.view) == region.begin() + 1:
                bol_is_nl = False
                bol_at_nl = False
            else:
                bol_is_nl = self.view.substr(region.begin() - 1) == "\n"
                bol_at_nl = (
                    l_brace == "{"
                    and self.view.substr(region.begin()) == "\n"
                    and self.view.substr(region.begin() - 1) != "\n"
                )
            eol_is_nl = region.end() == self.view.size() or self.view.substr(region.end()) == "\n"
            eol_at_nl = self.view.substr(region.end() - 1) == "\n"
            if eol_is_nl:
                eol_is_nl = self.view.line(region.begin()) != self.view.line(region.end())

            if real_brackets and (bol_is_nl or bol_at_nl) and (eol_is_nl or eol_at_nl):
                indent = ""
                if bol_at_nl and substitute:
                    substitute = substitute[1:]
                m = re.match("([ \t]*)" + tab, substitute)
                if m:
                    indent = m.group(1)
                else:
                    substitute = tab + substitute
                b = region.begin() - len("\n" + indent + r_brace)

                if bol_at_nl:
                    replacement = l_brace + "\n" + substitute
                    if eol_at_nl:
                        replacement += indent + r_brace + "\n"
                        b -= 1
                    else:
                        replacement += r_brace + "\n"
                        b += len(indent)

                    if not self.view.substr(region.begin() - 1) == " ":
                        replacement = " " + replacement
                else:
                    replacement = indent + l_brace + "\n" + substitute + indent + r_brace + "\n"
                    b -= 1
                b += len(replacement)
            else:
                b = region.begin() + len(replacement)

            if (
                replace
                and self.view.substr(region.begin() - 1) in OPENING_BRACKET_LIKE
                and self.view.substr(region.end()) in CLOSING_BRACKET_LIKE
            ):
                b -= 1
                self.view.replace(edit, Region(region.begin() - 1, region.end() + 1), replacement)
            elif (
                replace
                and self.view.substr(region.begin()) in OPENING_BRACKET_LIKE
                and self.view.substr(region.end() - 1) in CLOSING_BRACKET_LIKE
            ):
                replacement = l_brace + replacement[2:-2] + r_brace
                b -= 2
                self.view.replace(edit, region, replacement)
                l_brace = r_brace = ""
            else:
                self.view.replace(edit, region, replacement)

            if select:
                self.view.sel().add(Region(b - len(replacement) + len(l_brace), b - len(r_brace)))
            else:
                self.view.sel().add(Region(b, b))
예제 #35
0
    def run_each(self, edit, region, braces='{}', pressed=None, unindent=False, select=False, replace=False):
        self.view.sel().subtract(region)
        if self.view.settings().get('translate_tabs_to_spaces'):
            tab = ' ' * self.view.settings().get('tab_size')
        else:
            tab = "\t"

        row, col = self.view.rowcol(region.begin())
        indent_point = self.view.text_point(row, 0)
        if indent_point < region.begin():
            indent = self.view.substr(Region(indent_point, region.begin()))
            indent = re.match('[ \t]*', indent).group(0)
        else:
            indent = ''
        line = self.view.substr(self.view.line(region.a))
        selection = self.view.substr(region)

        # for braces that have newlines ("""), insert the current line's indent
        braces = braces.replace("\n", "\n" + indent)
        length = len(braces) / 2
        l_brace = braces[:length]
        r_brace = braces[length:]

        if region.empty():
            after = self.view.substr(Region(region.a, region.a + length))

            insert_braces = braces
            complicated_check = self.complicated_quote_checker(insert_braces, region, pressed, after, r_brace)

            if complicated_check:
                insert_braces = complicated_check
            elif pressed and after == r_brace and r_brace[-1] == pressed:  # and (pressed not in QUOTING_BRACKETS or in_string_scope):
                # in this case we pressed the closing character, and that's the character that is to the right
                # so do nothing except advance cursor position
                insert_braces = False
            elif unindent and row > 0 and indent and line == indent:
                # indent has the current line's indent
                # get previous line's indent:
                prev_point = self.view.text_point(row - 1, 0)
                prev_line = self.view.line(prev_point)
                prev_indent = self.view.substr(prev_line)
                prev_indent = re.match('[ \t]*', prev_indent).group(0)

                if (not pressed or pressed == l_brace) and len(indent) > len(prev_indent) and indent[len(prev_indent):] == tab:
                    # move region.a back by 'indent' amount
                    region = Region(region.a - len(tab), region.b - len(tab))
                    # and remove the tab
                    self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), '')
                elif pressed and pressed == r_brace:
                    if len(indent) == len(prev_indent):
                        # move region.a back by 'indent' amount
                        region = Region(region.a - len(tab), region.b - len(tab))
                        # and remove the tab
                        self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), '')
                    insert_braces = r_brace
            elif pressed and pressed != l_brace:
                # we pressed the closing bracket or quote.  This *never*
                insert_braces = r_brace

            if insert_braces:
                self.view.insert(edit, region.a, insert_braces)
            self.view.sel().add(Region(region.a + length, region.a + length))
        elif selection in QUOTING_BRACKETS and pressed in QUOTING_BRACKETS and selection != pressed:
            # changing a quote from single <=> double, just insert the quote.
            self.view.replace(edit, region, pressed)
            self.view.sel().add(Region(region.end(), region.end()))
        elif pressed and pressed != l_brace:
            b = region.begin() + len(r_brace)
            self.view.replace(edit, region, r_brace)
            self.view.sel().add(Region(b, b))
        else:
            substitute = self.view.substr(region)
            replacement = l_brace + substitute + r_brace
            # if we're inserting "real" brackets, not quotes:
            real_brackets = l_brace in OPENING_BRACKETS and r_brace in CLOSING_BRACKETS
            # check to see if entire lines are selected, and if so do some smart indenting
            bol_is_nl = region.begin() == 0 or self.view.substr(region.begin() - 1) == "\n"
            eol_is_nl = region.end() == self.view.size() - 1 or self.view.substr(region.end() - 1) == "\n"
            if real_brackets and bol_is_nl and eol_is_nl:
                indent = ''
                final = ''
                m = re.match('([ \t]*)' + tab, self.view.substr(region))
                if m:
                    indent = m.group(1)
                    final = "\n"
                else:
                    substitute = tab + substitute
                replacement = indent + l_brace + "\n" + substitute + indent + r_brace + final
                b = region.begin() + len(replacement) - len("\n" + indent + r_brace + final)
            else:
                b = region.begin() + len(replacement)

            if replace and self.view.substr(region.begin() - 1) in OPENING_BRACKET_LIKE and self.view.substr(region.end()) in CLOSING_BRACKET_LIKE:
                b -= 1
                self.view.replace(edit, Region(region.begin() - 1, region.end() + 1), replacement)
            elif replace and self.view.substr(region.begin()) in OPENING_BRACKET_LIKE and self.view.substr(region.end() - 1) in CLOSING_BRACKET_LIKE:
                replacement = l_brace + replacement[2:-2] + r_brace
                b -= 2
                self.view.replace(edit, region, replacement)
                l_brace = r_brace = ''
            else:
                self.view.replace(edit, region, replacement)

            if select:
                self.view.sel().add(Region(b - len(replacement) + len(l_brace), b - len(r_brace)))
            else:
                self.view.sel().add(Region(b, b))
예제 #36
0
def region_to_range(view: sublime.View, region: sublime.Region) -> 'Range':
    return Range(offset_to_point(view, region.begin()),
                 offset_to_point(view, region.end()))
예제 #37
0
def uncomment_region(view, edit, region):
    begin = region.begin()
    end = region.end() - 1

    # We will loop backwards, this means that it will hit the closing
    # punctuation for block comments first.
    i = end + 1
    while i > begin:
        i -= 1
        scopes = view.scope_name(i)

        # Not a punctuation, ignore it.
        if 'punctuation.definition.comment' not in scopes:
            continue

        # Found the second forward slash for the “// ” comment.
        if 'comment.line' in scopes:
            punctuation_region = generate_comment_punctuation_region(view, i)
            view.erase(edit, punctuation_region)
            i = punctuation_region.begin()
            continue

        # We found the beginning of the block comment first, this means that
        # there’s no end to it and we can easily remove it. It can be “/* ”,
        # “/** ”, “{/* ” or “{/** ”.
        if 'punctuation.definition.comment.begin' in scopes:
            punctuation_region = generate_jsjsx_comment_punctuation_region(
                view, i
            )

            view.erase(edit, punctuation_region)
            i = punctuation_region.begin()
            continue

        # We are looping backwards, so it is expected to find the closing
        # punctuation first which can be “ */” or “ */}”.
        possible_jsx_comment = False
        if i < view.size() and is_jsx_close_brace(view, i + 1):
            possible_jsx_comment = True

        closing_punctuation_region = generate_comment_punctuation_region(
            view, i
        )

        # Move the cursor 1 character after the beginning punctuation.
        i = scan_reverse(view, i, not_predicate(has_scope_predicate(
            'punctuation.definition.comment.begin'
        )))

        open_punctuation_region = generate_comment_punctuation_region(
            view, i - 1
        )

        # Correct the regions to include the JSX braces if necessary.
        if possible_jsx_comment:
            if is_jsx_open_brace(view, open_punctuation_region.begin() - 1):
                open_punctuation_region = Region(
                    open_punctuation_region.begin() - 1,
                    open_punctuation_region.end()
                )
                closing_punctuation_region = Region(
                    closing_punctuation_region.begin(),
                    closing_punctuation_region.end() + 1
                )

        view.erase(edit, closing_punctuation_region)
        view.erase(edit, open_punctuation_region)

        # Move the cursor to the beginning of the block to “consume” it.
        i = open_punctuation_region.begin()