Skip to content

Commit

Permalink
Merge pull request #18 from ilyakam/release/1.2.1
Browse files Browse the repository at this point in the history
chore(*): release version 1.2.1
  • Loading branch information
ilyakam authored Jun 3, 2018
2 parents f9ae8e9 + 49c76cb commit 2043532
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 24 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [1.2.1] - 2018-06-03
### Fixed:
- Ensure that lines of different lengths are not concatenated together
- Ensure that trailing lines are preserved

## [1.2.0] - 2018-05-15
### Added:
- Installation instructions to the `README`
Expand Down
77 changes: 53 additions & 24 deletions remove_duplicate_lines.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,73 @@
import sublime
import sublime_plugin
from collections import OrderedDict

class RemoveDuplicateLinesCommand(sublime_plugin.TextCommand):
def run(self, edit):
"""
Removes duplicate lines so that each line contains a unique string
If a line is selected, it removes duplicate occurrences ONLY of the selection
If a line is selected, it removes ONLY its duplicate occurrences elsewhere
in the file
"""

def delete_lines(needle, lines):
def dedupe_file():
"""
Marks lines for deletion one by one and deletes them all at once
Removes duplicates from the entire file by splitting it into lines, adding
them into an `OrderedDict` which preserves order and removes duplicates,
and combines everything back into a string with newlines
"""
needle_contents = self.view.substr(needle)
needle_size = needle.size()

for line in lines:
# Improve performance by comparing sizes before contents:
if (needle_size == line.size() and
needle_contents == self.view.substr(line)):
lines = self.view.substr(sublime.Region(0, self.view.size())).splitlines()

# Mark line for deletion by adding it to the selection:
self.view.sel().add(self.view.full_line(line))
text = '\n'.join(OrderedDict.fromkeys(lines))

# Avoid deleting the existing selection, if any
self.view.sel().subtract(needle)
replace(text)

# Delete all selections in reverse order to preserve the cursor position:
for deletion_selection in reversed(self.view.sel()):
self.view.erase(edit, deletion_selection)
def dedupe_selection(selection):
"""
Removes duplicates from the rest of the file where the selection exists on
other lines by keeping the lines that do not match the selection and
recombining them back into a string with newlines
"""

self.view.sel().clear()
lines = []

for line in self.view.lines(sublime.Region(0, self.view.size())):
is_other_line = (self.view.substr(line) != self.view.substr(selection)
or (line.begin() == selection.begin()
and line.end() == selection.end()))

if is_other_line:
lines.append(self.view.substr(line))

for region in self.view.sel():
# Select the entire file:
lines = self.view.lines(sublime.Region(0, self.view.size()))
text = '\n'.join(lines)

replace(text)

def main():
"""
Removes duplicates from non-empty selections only when they exist;
otherwise, removes duplicates from the entire file
"""

if region.empty():
while len(lines) > 0:
delete_lines(lines.pop(0), lines)
non_empty_selections = [selection for selection in self.view.sel()
if not selection.empty()]

if non_empty_selections:
[dedupe_selection(selection)
for selection in reversed(non_empty_selections)]

else:
delete_lines(region, lines)
dedupe_file()

def replace(text):
"""
Replaces the entire file with text and moves the cursor to the top
"""

self.view.replace(edit, sublime.Region(0, self.view.size()), text)
self.view.sel().clear()

self.view.sel().add(0)

main()

0 comments on commit 2043532

Please sign in to comment.