Skip to content

Commit

Permalink
Sort plugin: use indentation when deciding lines to sort
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli committed Jul 12, 2023
1 parent 32d7b29 commit 0d1390f
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 9 deletions.
38 changes: 29 additions & 9 deletions porcupine/plugins/sort.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
"""
Sort the selected lines alphabetically, or if there's no selection, sort between surrounding blank lines.
Sort the selected lines alphabetically. Available in menubar → Edit → Sort Lines.
Available in Edit/Sort Lines.
To sort lines that are indented or surrounded by blank lines, you can simply
place the cursor somewhere in the middle without selecting anything and run the
sort. In other words, if there is nothing selected, this plugin will select
lines above and below the cursor location, excluding blank lines or any lines
with less indentation.
"""

from __future__ import annotations
import tkinter

from porcupine import menubar, tabs, textutils


def can_extend_default_selection(text: tkinter.Text, required_prefix: str, new_lineno: int) -> bool:
line = text.get(f"{new_lineno}.0", f"{new_lineno + 1}.0")
return bool(line.strip()) and line.startswith(required_prefix)


def find_chunk_around_cursor(text: tkinter.Text) -> tuple[int, int]:
cursor_lineno = int(text.index("insert").split(".")[0])
cursor_line = text.get("insert linestart", "insert lineend")
cursor_line_indentation = cursor_line[:(len(cursor_line) - len(cursor_line.lstrip()))]

start = cursor_lineno
while can_extend_default_selection(text, cursor_line_indentation, start - 1):
start -= 1

end = cursor_lineno
while can_extend_default_selection(text, cursor_line_indentation, end + 1):
end += 1

return (start, end)


def sort(tab: tabs.FileTab) -> None:
try:
first_line = int(tab.textwidget.index("sel.first").split(".")[0])
# If last selected character is newline, ignore it
last_line = int(tab.textwidget.index("sel.last - 1 char").split(".")[0])
except tkinter.TclError:
# Nothing selected, find blank line separated part
first_line = last_line = int(tab.textwidget.index("insert").split(".")[0])
while tab.textwidget.get(f"{first_line - 1}.0", f"{first_line}.0").strip():
first_line -= 1
while tab.textwidget.get(f"{last_line + 1}.0", f"{last_line + 2}.0").strip():
last_line += 1
first_line, last_line = find_chunk_around_cursor(tab.textwidget)

old_lines = tab.textwidget.get(f"{first_line}.0", f"{last_line}.0 lineend").splitlines()
new_lines = sorted(old_lines)
Expand Down
31 changes: 31 additions & 0 deletions tests/test_sort_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,37 @@ def test_finding_blank_line_separated_block(filetab):
)


def test_finding_indented_block(filetab):
filetab.textwidget.insert(
"end",
"""\
[foo]
dingdingding
akuli
catris
banana
blah blah
""")

filetab.textwidget.mark_set("insert", "3.3")
filetab.event_generate("<<Menubar:Edit/Sort Lines>>")
assert filetab.textwidget.index("insert") == "3.3" # not moved
assert (
filetab.textwidget.get("1.0", "end - 1 char")
== """\
[foo]
akuli
banana
catris
dingdingding
blah blah
"""
)
assert filetab.textwidget.get("sel.first", "sel.last") == " akuli\n banana\n catris\n dingdingding\n"


def test_just_sorting_the_whole_file(filetab):
filetab.textwidget.insert("end", "bbb\nccc\naaa")
filetab.textwidget.mark_set("insert", "2.0")
Expand Down

0 comments on commit 0d1390f

Please sign in to comment.