Example #1
0
def calculate_buffer_search_flags(view, pattern):
    flags = 0

    if get_option(view, 'ignorecase'):
        flags |= IGNORECASE

    if not get_option(view, 'magic'):
        flags |= LITERAL
    elif pattern:
        # In magic mode some characters in the pattern are taken literally. They
        # match with the same character in the text e.g. ], '], "[ are taken
        # literally and patterns like [0-9], .+, ^, are regular expressions.

        # XXX Note that this is a very rough hacky implementation to support
        # some obvious patterns that should be taken literally like [ and "[.

        if re.match('^[a-zA-Z0-9_\'"\\[\\]]+$', pattern):
            if '[' not in pattern or ']' not in pattern:
                flags |= LITERAL

        elif re.match('^[a-zA-Z0-9_\'"\\(\\)]+$', pattern):
            if '(' not in pattern or ')' not in pattern:
                flags |= LITERAL

    return flags
Example #2
0
def add_search_highlighting(view, occurrences, incremental=None):
    if get_option(view, 'incsearch') and incremental:
        view.add_regions('_nv_search_inc',
                         incremental,
                         scope='support.function neovintageous_search_inc',
                         flags=ui_region_flags(
                             get_setting_neo(view, 'search_inc_style')))

    if get_option(view, 'hlsearch'):
        sels = view.sel()

        # TODO Optimise
        current = []
        for region in occurrences:
            for sel in sels:
                if region.contains(sel):
                    current.append(region)

        view.add_regions('_nv_search_occ',
                         occurrences,
                         scope='string neovintageous_search_occ',
                         flags=ui_region_flags(
                             get_setting_neo(view, 'search_occ_style')))

        view.add_regions('_nv_search_cur',
                         current,
                         scope='support.function neovintageous_search_cur',
                         flags=ui_region_flags(
                             get_setting_neo(view, 'search_cur_style')))
Example #3
0
def find_wrapping(view,
                  term: str,
                  start: int,
                  end: int,
                  flags: int = 0,
                  times: int = 1):
    try:
        current_sel = view.sel()[0]
    except IndexError:
        return

    for x in range(times):
        match = find_in_range(view, term, start, end, flags)
        # make sure we wrap around the end of the buffer
        if not match:
            if not get_option(view, 'wrapscan'):
                return

            start = 0
            # Extend the end of search to the end of current word, because
            # otherwise the current word would be excluded and not found.
            # See https://github.com/NeoVintageous/NeoVintageous/issues/223.
            end = current_sel.a
            end = view.word(current_sel.a).b
            match = find_in_range(view, term, start, end, flags)
            if not match:
                return

        start = match.b

    return match
Example #4
0
def calculate_word_search_flags(view, pattern):
    flags = 0

    if get_option(view, 'ignorecase'):
        flags |= IGNORECASE

    return flags
Example #5
0
def reverse_find_wrapping(view,
                          term: str,
                          start: int,
                          end: int,
                          flags: int = 0,
                          times: int = 1):
    try:
        current_sel = view.sel()[0]
    except IndexError:
        return

    # Search wrapping around the end of the buffer.
    for x in range(times):
        match = reverse_search(view, term, start, end, flags)
        # Start searching in the lower half of the buffer if we aren't doing it yet.
        if not match and start <= current_sel.b:
            if not get_option(view, 'wrapscan'):
                return

            # Extend the start of search to start of current word, because
            # otherwise the current word would be excluded and not found.
            # See https://github.com/NeoVintageous/NeoVintageous/issues/223.
            start = view.word(current_sel.b).a
            end = view.size()
            match = reverse_search(view, term, start, end, flags)
            if not match:
                return
        # No luck in the whole buffer.
        elif not match:
            return

        end = match.a

    return match
Example #6
0
def _ui_bell(*msg: str) -> None:
    window = active_window()
    if not window:
        return

    view = window.active_view()
    if not view:
        return

    if msg:
        status_message(*msg)

    if get_option(view, 'belloff') == 'all':
        return

    color_scheme = get_setting(view, 'bell_color_scheme')
    if color_scheme in ('dark', 'light'):
        color_scheme = 'Packages/NeoVintageous/res/Bell-%s.hidden-color-scheme' % color_scheme

    duration = int(0.3 * 1000)
    times = 4
    delay = 55

    style = get_setting(view, 'bell')

    settings = view.settings()

    if style == 'view':
        settings.set('color_scheme', color_scheme)

        def remove_bell() -> None:
            settings.erase('color_scheme')

        set_timeout(remove_bell, duration)
    elif style == 'views':
        views = []
        for group in range(window.num_groups()):
            view = window.active_view_in_group(group)
            if view:
                view.settings().set('color_scheme', color_scheme)
                views.append(view)

        def remove_bell() -> None:
            for view in views:
                view.settings().erase('color_scheme')

        set_timeout(remove_bell, duration)
    elif style == 'blink':
        # Ensure we leave the setting as we found it.
        times = times if (times % 2) == 0 else times + 1

        def do_blink() -> None:
            nonlocal times
            if times > 0:
                settings.set('highlight_line', not settings.get('highlight_line'))
                times -= 1
                set_timeout(do_blink, delay)

        do_blink()
Example #7
0
    def on_post_save(self, view):
        if get_option(view, 'modeline'):
            do_modeline(view)

        # Ensure the carets are within valid bounds. For instance, this is a
        # concern when 'trim_trailing_white_space_on_save' is set to true.
        # TODO Kill State dependency
        fix_eol_cursor(view, State(view).mode)
Example #8
0
def _get_search_flags(view, search: str) -> int:
    flags = LITERAL

    if search and get_setting(view, 'sneak_use_ic_scs') == 1:
        if get_option(view,
                      'ignorecase') and not is_smartcase_pattern(view, search):
            flags |= IGNORECASE

    return flags
Example #9
0
def process_word_search_pattern(view, pattern: str) -> tuple:
    flags = 0

    if get_option(view, 'ignorecase'):
        flags |= IGNORECASE

    pattern = r'\b{0}\b'.format(re.escape(pattern))

    return pattern, flags
def filter_region(view, text: str, cmd: str) -> str:
    # Redirect STDERR to STDOUT to capture both.
    # This seems to be the behavior of vim as well.
    p = subprocess.Popen([get_option(view, 'shell'), '-c', cmd],
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)

    # Pass in text as input: saves having to deal with quoting stuff.
    out, _ = p.communicate(text.encode('utf-8'))

    return out.decode('utf-8', errors='backslashreplace')
Example #11
0
def add_search_highlighting(view,
                            occurrences: list,
                            incremental: list = None) -> None:
    # Incremental search match string highlighting: while typing a search
    # command, where the pattern, as it was typed so far, matches.
    if incremental and get_option(view, 'incsearch'):
        view.add_regions('_nv_search_inc',
                         incremental,
                         scope='support.function neovintageous_search_inc',
                         flags=ui_region_flags(
                             get_setting_neo(view, 'search_inc_style')))

    # Occurrences and current search match string highlighting: when there are
    # search matches, highlight all the matches and the current active one too.
    if occurrences and get_option(view, 'hlsearch'):
        view.add_regions('_nv_search_occ',
                         occurrences,
                         scope='string neovintageous_search_occ',
                         flags=ui_region_flags(
                             get_setting_neo(view, 'search_occ_style')))

        sels = []
        for sel in view.sel():
            if sel.empty():
                sel.b += 1
            sels.append(sel)

        current = []
        for region in occurrences:
            for sel in sels:
                if region.contains(sel):
                    current.append(region)

        if current:
            view.add_regions('_nv_search_cur',
                             current,
                             scope='support.function neovintageous_search_cur',
                             flags=ui_region_flags(
                                 get_setting_neo(view, 'search_cur_style')))
def read(view, cmd: str) -> str:
    p = subprocess.Popen([get_option(view, 'shell'), '-c', cmd],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)

    out, err = p.communicate()

    if out:
        return out.decode('utf-8')

    if err:
        return err.decode('utf-8')

    return ''
Example #13
0
def wrapscan(view, forward=True):
    start = list(view.sel())

    yield

    if not get_option(view, 'wrapscan'):
        for before, after in zip(start, list(view.sel())):
            if forward:
                if after.a < before.a:
                    set_selection(view, start)
                    break
            else:
                if after.a > before.a:
                    set_selection(view, start)
                    break
Example #14
0
def read(view, cmd: str) -> str:
    p = subprocess.Popen([get_option(view, 'shell'), '/c', cmd],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         startupinfo=_get_startup_info())

    out, err = p.communicate()

    if out:
        return _translate_newlines(out.decode(_get_encoding()))

    if err:
        return _translate_newlines(err.decode(_get_encoding()))

    return ''
Example #15
0
    def __init__(self, window, type: str, on_done=None, on_change=None, on_cancel=None):
        self._window = window

        if type not in self._TYPES:
            raise ValueError('invalid cmdline type')

        self._type = type

        # TODO Make view a contructor dependency? window.active_view() is a race-condition whereas view.window() isn't
        if type in (self.SEARCH_FORWARD, self.SEARCH_BACKWARD) and not get_option(window.active_view(), 'incsearch'):
            on_change = None

        self._callbacks = {
            'on_done': on_done,
            'on_change': on_change,
            'on_cancel': on_cancel,
        }
Example #16
0
def wrapscan(view, forward: bool = True):
    # This works by comparing the postion of the cursor after the enclosed
    # operation. If wrapscan is disabled and the cursor position has "wrapped
    # around" then it's reset to the previous postion before it was wrapped.
    start = list(view.sel())

    yield

    if not get_option(view, 'wrapscan'):
        for before, after in zip(start, list(view.sel())):
            if forward:
                if after.a < before.a:
                    set_selection(view, start)
                    break
            else:
                if after.a > before.a:
                    set_selection(view, start)
                    break
Example #17
0
def _is_alt_key_enabled(view, operator, operand, match_all):
    # Some GUI versions allow the access to menu entries by using the ALT
    # key in combination with a character that appears underlined in the
    # menu.  This conflicts with the use of the ALT key for mappings and
    # entering special characters.  This option tells what to do:
    #   no    Don't use ALT keys for menus.  ALT key combinations can be
    #         mapped, but there is no automatic handling.
    #   yes   ALT key handling is done by the windowing system.  ALT key
    #         combinations cannot be mapped.
    #   menu  Using ALT in combination with a character that is a menu
    #         shortcut key, will be handled by the windowing system.  Other
    #         keys can be mapped.
    # If the menu is disabled by excluding 'm' from 'guioptions', the ALT
    # key is never used for the menu.
    winaltkeys = get_option(view, 'winaltkeys')
    if winaltkeys == 'menu':
        return (operand not in tuple('efghinpstv') or
                not view.window().is_menu_visible()) and _is_command_mode(view)

    return False if winaltkeys == 'yes' else _is_command_mode(view)
Example #18
0
def do_modeline(view) -> None:
    # A feature similar to vim modeline. A number of lines at the beginning and
    # end of the file are checked for modelines. The number of lines checked is
    # controlled by the 'modelines' option, the default is 5.
    #
    # Examples:
    #   vim: number
    #   vim: nonumber
    #   vim: tabstop=4
    #   vim: ts=4 noet
    window = view.window()

    # If the view is "transient" (for example when opened in in preview via the
    # CTRL-p overlay) then the view won't have a window object. Some ST events
    # like on_load() may open transient views.
    if not window:
        window = active_window()

    if window:
        modelines = get_option(view, 'modelines')
        line_count = view.rowcol(view.size())[0] + 1
        head_lines = range(0, min(modelines, line_count))
        tail_lines = range(max(0, line_count - modelines), line_count)
        lines = list(set(list(head_lines) + list(tail_lines)))

        for i in lines:
            line = view.line(view.text_point(i, 0))
            if line.size() > 0:
                options = _parse_line(view.substr(line))
                if options:
                    for option in options:
                        if option.strip().startswith('shell'):
                            message('Error detected while processing modelines:')
                            message('line %s:', str(i + 1))
                            message('E520: Not allowed in a modeline: %s', option)
                        else:
                            do_ex_cmdline(window, ':setlocal ' + option)
Example #19
0
def _gen_modeline_options(view):
    modelines = _gen_modelines(view, get_option(view, 'modelines'))
    for opt in _gen_raw_options(modelines):
        name, sep, value = opt.partition(' ')
        yield view.settings().set, name.rstrip(':'), value.rstrip(';')
Example #20
0
 def on_load(self, view):
     if is_view(view) and get_option(view, 'modeline'):
         do_modeline(view)
Example #21
0
def _is_alt_key_enabled(view, operator, operand, match_all):
    winaltkeys = get_option(view, 'winaltkeys')
    if winaltkeys == 'menu':
        return (operand not in tuple('efghinpstv') or not view.window().is_menu_visible()) and _is_command_mode(view)

    return False if winaltkeys == 'yes' else _is_command_mode(view)
Example #22
0
 def on_load(self, view):
     if get_option(view, 'modeline'):
         do_modeline(view)
Example #23
0
def process_search_pattern(view, pattern: str) -> tuple:
    flags = 0

    if get_option(view,
                  'ignorecase') and not is_smartcase_pattern(view, pattern):
        flags |= IGNORECASE

    # Changes the special characters that can be used in search patterns.
    is_magic = get_option(view, 'magic')

    # Pattern modes can be specified anywhere within the pattern itself and the
    # effect of the mode applies to the entire pattern:
    #
    # \c  ignore case, do not use the 'ignorecase' option
    # \C  match case, do not use the 'ignorecase' option
    pattern_modes = set()

    def _add_pattern_mode(match) -> str:
        pattern_modes.add(match.group(1))
        return ''

    pattern = re.sub('\\\\([cC])', _add_pattern_mode, pattern)
    for m in pattern_modes:
        if m == 'c':
            flags |= IGNORECASE
        elif m == 'C':
            flags &= ~IGNORECASE

    # Some characters in the pattern are taken literally. They match with the
    # same character in the text. When preceded with a backslash however, these
    # characters get a special meaning. See :help magic for more details.
    #
    # Patterns can be prefixed by a "mode" that overrides the 'magic' option:
    #
    #   \m    'magic' on for the following chars in the pattern.
    #   \M    'magic' off for the following chars in the pattern.
    #   \v    the following chars in the pattern are "very magic".
    #   \V    the following chars int the pattern are "very nomagic".
    mode = None
    match = re.match('^\\\\(m|M|v|V)(.*)$', pattern)
    if match:
        mode = match.group(1)
        pattern = match.group(2)

    def _process_magic(pattern, flags):
        # When magic is on some characters in a pattern are interpreted
        # literally depending on context. For example [0-9 is interpreted
        # literally and [0-9] is interpreted as a regular expression.
        # XXX The following is a quick and dirty implementation to support some
        # very basic 'magic' literal interpretations.
        if pattern:
            if re.match('^[a-zA-Z0-9_\'"\\[\\]]+$', pattern):
                if '[' not in pattern or ']' not in pattern:
                    flags |= LITERAL

            elif re.match('^[a-zA-Z0-9_\'"\\(\\)]+$', pattern):
                if '(' not in pattern or ')' not in pattern:
                    flags |= LITERAL

        return pattern, flags

    # magic
    if mode == 'm' or (is_magic and not mode):
        pattern, flags = _process_magic(pattern, flags)

    # very magic
    elif mode == 'v':
        pattern, flags = _process_magic(pattern, flags)

    # nomagic
    elif mode == 'M' or (not is_magic and not mode):
        flags |= LITERAL

    # very nomagic
    elif mode == 'V':
        flags |= LITERAL

    return pattern, flags
Example #24
0
def is_smartcase_pattern(view, pattern: str) -> bool:
    return get_option(view, 'smartcase') and any(p.isupper() for p in pattern)