Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mwean committed Oct 30, 2013
1 parent 8fc6157 commit 2d6327b
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Default.sublime-keymap
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{ "keys": ["alt+up"], "command": "jump_prev_indent" },
{ "keys": ["alt+shift+up"], "command": "jump_prev_indent", "args": { "extend_selection": true} },
{ "keys": ["alt+down"], "command": "jump_next_indent" },
{ "keys": ["alt+shift+down"], "command": "jump_next_indent", "args": { "extend_selection": true} }
]
Empty file added __init__.py
Empty file.
115 changes: 115 additions & 0 deletions file_scanner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import sublime, re
from .view_helper import ViewHelper

class FileScanner:
def __init__(self, view):
self.view = view
self.view_helper = ViewHelper(view)

def scan_from_beginning(self, direction = 'forward'):
search_start = self.next_line(self.view_helper.initial_selection().begin())
return self.search(self.search_str(), search_start) - 1

def scan_from_end(self, direction = 'forward'):
view_helper = self.view_helper
search_start = view_helper.find_bol(view_helper.initial_selection().begin())
search_end = self.previous_line(view_helper.initial_selection().end())
return self.reverse_search(self.search_str(), search_start, search_end) - 1

def scan(self, direction = 'forward'):
if direction == 'forward':
return self.search(self.search_str(), self.next_line()) - 1
else:
return self.reverse_search(self.search_str(), 0, self.previous_line()) - 1

def search_str(self):
if re.match(r"^\s*$", self.str_to_left()) and re.match(r"^\s+\S+", self.str_to_right()):
search_str = "^ {0," + str(len(self.str_to_left())) + "}\S+"
else:
search_str = "^" + self.leading_spaces() + "\S"
return search_str

def str_to_left(self):
view = self.view
sel_pt = self.view_helper.initial_cursor_position()
left_pt = view.line(sel_pt).a
left_region = sublime.Region(left_pt, sel_pt)
return view.substr(left_region)

def str_to_right(self):
view = self.view
sel_pt = self.view_helper.initial_cursor_position()
right_pt = view.line(sel_pt).b
right_region = sublime.Region(sel_pt, right_pt)
return view.substr(right_region)

def leading_spaces(self):
spaces = re.match(r"(\s*)", self.current_line())
return spaces.group(0)

def current_line(self):
view = self.view
line_region = view.line(self.view_helper.initial_cursor_position())
return view.substr(line_region)

def previous_line(self, position = None):
position = position or self.view_helper.initial_cursor_position()
return self.view.line(position).a - 1

def next_line(self, position = None):
position = position or self.view_helper.initial_cursor_position()
view = self.view
return view.rowcol(view.line(position).b + 1)[0]

def search(self, pattern, start_line = None, flags = 0):
view = self.view

if start_line:
start = view.text_point(start_line, 0)
else:
start = self.view_helper.initial_cursor_position().begin()
reg = view.find(pattern, start, flags)

if not reg is None:
row = (view.rowcol(reg.begin())[0] + 1)
else:
row = self.calculate_relative_ref('.', start_line = start_line)
return row

def reverse_search(self, pattern, start = 0, end = -1, flags = 0):
view = self.view

if end == -1:
end = view.size()

end = self.view_helper.find_eol(view.line(end).a)
match = self.find_last_match(pattern, start, end)
return view.rowcol(match.begin())[0] + 1

def search_in_range(self, pattern, start, end, flags = 0):
match = self.view.find(pattern, start, flags)
if match and ((match.begin() >= start) and (match.end() <= end)):
return True

def find_last_match(self, pattern, start, end, flags = 0):
"""Find last occurrence of `pattern` between `start`, `end`.
"""
view = self.view
match = view.find(pattern, start, flags)
new_match = None
while match:
new_match = view.find(pattern, match.end(), flags)
if new_match and new_match.end() <= end:
match = new_match
else:
return match

def calculate_relative_ref(self, where, start_line = None):
view = self.view

if where == '$':
return view.rowcol(view.size())[0] + 1
if where == '.':
if start_line:
return view.rowcol(view.text_point(start_line, 0))[0] + 1
return view.rowcol(view.sel()[0].begin())[0] + 1
79 changes: 79 additions & 0 deletions jump_along_indent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import sublime, sublime_plugin, re, sys
from .file_scanner import FileScanner
from .view_helper import ViewHelper

def cursor_position(view):
return view.sel()[0]

def build_selection(view, new_region, target):
view.sel().clear()
view.sel().add(new_region)
view.show(target)

class JumpNextIndentCommand(sublime_plugin.TextCommand):
def run(self, edit, extend_selection = False):
view = self.view
self.view_helper = ViewHelper(view)
self.scanner = FileScanner(view)
cursor_at_top_of_selection = self.view_helper.cursor_at_top_of_selection()

if not extend_selection:
self.jump_downward()
elif cursor_at_top_of_selection:
self.deselect_downward()
else:
self.select_downward()

def jump_downward(self):
target = self.target_point()
new_region = sublime.Region(target)
build_selection(self.view, new_region, target)

def select_downward(self):
target = self.target_point()
new_region = sublime.Region(self.view_helper.initial_selection().begin(), target)
build_selection(self.view, new_region, target)

def deselect_downward(self):
matched_point = self.scanner.scan_from_beginning()
target = self.target_point(matched_point)
new_region = sublime.Region(self.view_helper.initial_selection().end(), target)
build_selection(self.view, new_region, target)

def target_point(self, matched_point = None):
matched_point = matched_point or self.scanner.scan()
return self.view.text_point(matched_point, self.view_helper.target_column(matched_point))

class JumpPrevIndentCommand(sublime_plugin.TextCommand):
def run(self, edit, extend_selection = False):
view = self.view
self.view_helper = ViewHelper(view)
self.scanner = FileScanner(view)
cursor_at_bottom_of_selection = self.view_helper.cursor_at_bottom_of_selection()

if not extend_selection:
self.jump_upward()
elif cursor_at_bottom_of_selection:
self.deselect_upward()
else:
self.select_upward()

def jump_upward(self):
target = self.target_point()
new_region = sublime.Region(target)
build_selection(self.view, new_region, target)

def select_upward(self):
target = self.target_point()
new_region = sublime.Region(self.view_helper.initial_selection().end(), target)
build_selection(self.view, new_region, target)

def deselect_upward(self):
matched_point = self.scanner.scan_from_end(direction = 'backward')
target = self.target_point(matched_point)
new_region = sublime.Region(self.view_helper.initial_selection().begin(), target)
build_selection(self.view, new_region, target)

def target_point(self, matched_point = None):
matched_point = matched_point or self.scanner.scan(direction = 'backward')
return self.view.text_point(matched_point, self.view_helper.target_column(matched_point))
32 changes: 32 additions & 0 deletions view_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class ViewHelper:
def __init__(self, view):
self.view = view

def initial_cursor_position(self):
return self.initial_selection().b

def initial_selection(self):
return self.view.sel()[0]

def initial_column(self):
return self.view.rowcol(self.initial_cursor_position())[1]

def cursor_at_top_of_selection(self):
return self.initial_selection().a > self.initial_selection().b

def cursor_at_bottom_of_selection(self):
return self.initial_selection().b > self.initial_selection().a

def target_column(self, target):
end_of_line = self.find_eol(target)

if self.initial_column() > end_of_line:
return end_of_line
else:
return self.initial_column()

def find_eol(self, point):
return self.view.line(point).end()

def find_bol(self, point):
return self.view.line(point).begin()

0 comments on commit 2d6327b

Please sign in to comment.