def f(view, s): state = VintageState(view) if state.mode == MODE_NORMAL: if s.b == view.size(): return sublime.Region(view.size() - 1, view.size() - 1) elif view.substr(s.b) == '\n': if not view.line(s.b).empty(): r = sublime.Region(s.b + 1, s.b + 1) pt = utils.next_non_white_space_char(view, r.b, white_space='\t ') return sublime.Region(pt, pt) if state.mode == MODE_VISUAL: if not utils.is_region_reversed(view, s): # FIXME: Moving from EMPTYLINE to NONEMPTYLINE should select FIRSTCHAR on NEXTLINE # only, but it selects a WORD and the FIRSTCHAR of the following WORD too. # When starting from an empty line, select only the FIRSTCHAR of the FIRSTWORD on # NEXTLINE. if view.size() == s.b: return sublime.Region(s.a, s.b) if ViExecutionState.select_word_begin_from_empty_line: ViExecutionState.reset_word_state() return sublime.Region(s.a, view.word(view.line(s.b).a).a + 1) # If after the motion we're on an empty line, stay there. if view.substr(s.b - 1) == '\n' and view.line(s.b - 1).empty(): return s # Always select the FIRSTCHAR of NEXTWORD skipping any WHITESPACE. # XXX: Possible infinite loop at EOF. pt = s.b while True: pt = utils.next_non_white_space_char(view, pt, white_space='\t ') # We're on an EMPTYLINE, so stay here. if view.substr(pt) == '\n' and view.line(pt).empty(): break # NEWLINECHAR after NONEMPTYLINE; keep going. elif view.substr(pt) == '\n': pt += 1 continue # Any NONWHITESPACECHAR; stop here. else: break s = sublime.Region(s.a, pt + 1) # Reversed selections... else: # Skip over NEWLINECHAR at EOL if on NONEMPTYLINE. if view.substr(s.b) == '\n' and not view.line(s.b).empty(): # FIXME: Don't swallow empty lines. pt = utils.next_non_white_space_char(view, s.b, white_space='\t \n') return sublime.Region(s.a, pt) return s
def testCanReset(self): ViExecutionState.select_word_begin_from_empty_line = True ViExecutionState.reset() self.assertFalse(ViExecutionState.select_word_begin_from_empty_line)
def f(view, s): state = VintageState(view) if state.mode == MODE_NORMAL: if s.b == view.size(): return sublime.Region(view.size() - 1, view.size() - 1) elif view.substr(s.b) == '\n': if not view.line(s.b).empty(): r = sublime.Region(s.b + 1, s.b + 1) pt = utils.next_non_white_space_char(view, r.b, white_space='\t ') return sublime.Region(pt, pt) if state.mode == MODE_VISUAL: if not utils.is_region_reversed(view, s): # FIXME: Moving from EMPTYLINE to NONEMPTYLINE should select FIRSTCHAR on NEXTLINE # only, but it selects a WORD and the FIRSTCHAR of the following WORD too. # When starting from an empty line, select only the FIRSTCHAR of the FIRSTWORD on # NEXTLINE. if view.size() == s.b: return sublime.Region(s.a, s.b) if ViExecutionState.select_word_begin_from_empty_line: ViExecutionState.reset_word_state() return sublime.Region( s.a, view.word(view.line(s.b).a).a + 1) # If after the motion we're on an empty line, stay there. if view.substr(s.b - 1) == '\n' and view.line(s.b - 1).empty(): return s # Always select the FIRSTCHAR of NEXTWORD skipping any WHITESPACE. # XXX: Possible infinite loop at EOF. pt = s.b while True: pt = utils.next_non_white_space_char(view, pt, white_space='\t ') # We're on an EMPTYLINE, so stay here. if view.substr(pt) == '\n' and view.line(pt).empty(): break # NEWLINECHAR after NONEMPTYLINE; keep going. elif view.substr(pt) == '\n': pt += 1 continue # Any NONWHITESPACECHAR; stop here. else: break s = sublime.Region(s.a, pt + 1) # Reversed selections... else: # Skip over NEWLINECHAR at EOL if on NONEMPTYLINE. if view.substr(s.b) == '\n' and not view.line(s.b).empty(): # FIXME: Don't swallow empty lines. pt = utils.next_non_white_space_char( view, s.b, white_space='\t \n') return sublime.Region(s.a, pt) if state.mode == _MODE_INTERNAL_NORMAL: if current_iteration == total_iterations: if view.substr(s.b - 1) == '\n' and not view.line(s.b - 1).empty(): return sublime.Region(s.a, s.b - 1) return s