From ab1c79d6355fc14a05b1cf8726040efa9bf37eef Mon Sep 17 00:00:00 2001 From: 1024jp <1024jp@wolfrosch.com> Date: Fri, 16 Oct 2015 14:11:00 +0900 Subject: [PATCH] Add "Delete Duplicates" action --- CHANGELOG.md | 2 +- CotEditor/Base.lproj/MainMenu.xib | 6 +++ CotEditor/CotEditor.sdef | 8 +++ CotEditor/Sources/CETextSelection.h | 1 + CotEditor/Sources/CETextSelection.m | 13 ++++- CotEditor/Sources/CETextView.h | 1 + CotEditor/Sources/CETextView.m | 59 +++++++++++++++++++++ CotEditor/de.lproj/Localizable.strings | 1 + CotEditor/de.lproj/MainMenu.strings | 2 + CotEditor/ja.lproj/Localizable.strings | 1 + CotEditor/ja.lproj/MainMenu.strings | 2 + CotEditor/zh-Hans.lproj/Localizable.strings | 1 + CotEditor/zh-Hans.lproj/MainMenu.strings | 2 + 13 files changed, 96 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3033c725..5411745af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ develop ### New Features - Introduce Auto Save and Versions as an option (in General pane). -- Add new “Move Line Up”, “Move Line Down”, “Sort Lines”, “Reverse Lines” and “Delete Line” actions to new Text menu. +- Add new actions handling selected lines to the new Text menu > Lines. - They are also added to the AppleScript terms. - Add “Spell Check” button to toolbar icon choices. - Customize toolbar to add it to your toolbar. diff --git a/CotEditor/Base.lproj/MainMenu.xib b/CotEditor/Base.lproj/MainMenu.xib index bebfe163e..fe9f4dfd0 100644 --- a/CotEditor/Base.lproj/MainMenu.xib +++ b/CotEditor/Base.lproj/MainMenu.xib @@ -682,6 +682,12 @@ + + + + + + diff --git a/CotEditor/CotEditor.sdef b/CotEditor/CotEditor.sdef index 1a1ea1658..d8960dae8 100644 --- a/CotEditor/CotEditor.sdef +++ b/CotEditor/CotEditor.sdef @@ -145,6 +145,9 @@ + + + @@ -285,6 +288,11 @@ + + + + + diff --git a/CotEditor/Sources/CETextSelection.h b/CotEditor/Sources/CETextSelection.h index 944a3988a..75d73b741 100644 --- a/CotEditor/Sources/CETextSelection.h +++ b/CotEditor/Sources/CETextSelection.h @@ -86,6 +86,7 @@ typedef NS_ENUM(NSUInteger, CEUNFType) { - (void)handleMoveLineDownScriptCommand:(NSScriptCommand *)command; - (void)handleSortLinesAscendingScriptCommand:(NSScriptCommand *)command; - (void)handleReverseLinesScriptCommand:(NSScriptCommand *)command; +- (void)handleDeleteDuplicateLineScriptCommand:(NSScriptCommand *)command; - (void)handleCommentOutScriptCommand:(NSScriptCommand *)command; - (void)handleUncommentScriptCommand:(NSScriptCommand *)command; - (void)handleChangeCaseScriptCommand:(NSScriptCommand *)command; diff --git a/CotEditor/Sources/CETextSelection.m b/CotEditor/Sources/CETextSelection.m index 02e459fc7..fc7fdc8e9 100644 --- a/CotEditor/Sources/CETextSelection.m +++ b/CotEditor/Sources/CETextSelection.m @@ -266,7 +266,7 @@ // ------------------------------------------------------ -/// swap selected lines with the line just below +/// sort selected lines ascending - (void)handleSortLinesAscendingScriptCommand:(NSScriptCommand *)command // ------------------------------------------------------ { @@ -275,7 +275,7 @@ // ------------------------------------------------------ -/// swap selected lines with the line just below +/// reverse selected lines - (void)handleReverseLinesScriptCommand:(NSScriptCommand *)command // ------------------------------------------------------ { @@ -283,6 +283,15 @@ } +// ------------------------------------------------------ +/// delete duplicate lines in selection +- (void)handleDeleteDuplicateLineScriptCommand:(NSScriptCommand *)command +// ------------------------------------------------------ +{ + [[[[self document] editor] focusedTextView] deleteDuplicateLine:command]; +} + + // ------------------------------------------------------ /// comment-out the selection - (void)handleCommentOutScriptCommand:(NSScriptCommand *)command diff --git a/CotEditor/Sources/CETextView.h b/CotEditor/Sources/CETextView.h index 1504934db..670b7d8a1 100644 --- a/CotEditor/Sources/CETextView.h +++ b/CotEditor/Sources/CETextView.h @@ -128,6 +128,7 @@ - (IBAction)moveLineDown:(nullable id)sender; - (IBAction)sortLinesAscending:(nullable id)sender; - (IBAction)reverseLines:(nullable id)sender; +- (IBAction)deleteDuplicateLine:(nullable id)sender; - (IBAction)deleteLine:(nullable id)sender; @end diff --git a/CotEditor/Sources/CETextView.m b/CotEditor/Sources/CETextView.m index b7d7e3503..26a69044a 100644 --- a/CotEditor/Sources/CETextView.m +++ b/CotEditor/Sources/CETextView.m @@ -2577,6 +2577,65 @@ static NSPoint kTextContainerOrigin; } +// ------------------------------------------------------ +/// remove duplicate lines in selection +- (IBAction)deleteDuplicateLine:(nullable id)sender +// ------------------------------------------------------ +{ + if ([self selectedRange].length == 0) { return; } + + NSMutableArray *replacementRanges = [NSMutableArray array]; + NSMutableArray *replacementStrings = [NSMutableArray array]; + NSMutableOrderedSet *uniqueLines = [NSMutableOrderedSet orderedSet]; + NSUInteger processedCount = 0; + + // collect duplicate lines + for (NSValue *rangeValue in [self selectedRanges]) { + NSRange range = [rangeValue rangeValue]; + NSRange lineRange = [[self string] lineRangeForRange:range]; + NSString *targetString = [[self string] substringWithRange:lineRange]; + NSArray *lines = [targetString componentsSeparatedByString:@"\n"]; + + // filter duplicate lines + [uniqueLines addObjectsFromArray:lines]; + + NSRange targetLinesRange = NSMakeRange(processedCount, [uniqueLines count] - processedCount); + processedCount += targetLinesRange.length; + + // do nothing if no duplicate line exists + if (targetLinesRange.length == [lines count]) { continue; } + + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:targetLinesRange]; + NSString *replacementString = [[uniqueLines objectsAtIndexes:indexSet] componentsJoinedByString:@"\n"]; + + // append last new line only if the original selected lineRange has a new line at the end + if ([targetString hasSuffix:@"\n"]) { + replacementString = [replacementString stringByAppendingString:@"\n"]; + } + + [replacementStrings addObject:replacementString]; + [replacementRanges addObject:[NSValue valueWithRange:lineRange]]; + } + + // return if no line to be removed + if ([replacementRanges count] == 0) { return; } + if (![self shouldChangeTextInRanges:replacementRanges replacementStrings:replacementStrings]) { return; } + + // delete duplicate lines + NSTextStorage *textStorage = [self textStorage]; + [replacementStrings enumerateObjectsWithOptions:NSEnumerationReverse + usingBlock:^(NSString *_Nonnull replacementString, NSUInteger idx, BOOL * _Nonnull stop) + { + NSRange replacementRange = [replacementRanges[idx] rangeValue]; + [textStorage replaceCharactersInRange:replacementRange withString:replacementString]; + }]; + [self didChangeText]; + + [[self undoManager] setActionName:NSLocalizedString(@"Delete Duplicate Lines", @"action name")]; +} + + + // ------------------------------------------------------ /// remove selected lines - (IBAction)deleteLine:(nullable id)sender diff --git a/CotEditor/de.lproj/Localizable.strings b/CotEditor/de.lproj/Localizable.strings index ebe78f4f8..88795a408 100644 --- a/CotEditor/de.lproj/Localizable.strings +++ b/CotEditor/de.lproj/Localizable.strings @@ -185,6 +185,7 @@ "Move Line" = "Zeile verschieben"; "Sort Lines" = "Zeilen sortieren"; "Reverse Lines" = "Zeilen umdrehen"; +"Remove Duplicate Lines" = "Doppelte Zeilen löschen"; "Delete Line" = "Zeile löschen"; // Menu items diff --git a/CotEditor/de.lproj/MainMenu.strings b/CotEditor/de.lproj/MainMenu.strings index 7a5d9c7d8..df1eab879 100644 --- a/CotEditor/de.lproj/MainMenu.strings +++ b/CotEditor/de.lproj/MainMenu.strings @@ -327,6 +327,8 @@ "OQl-Uo-yfn.title" = "Sortieren"; /* Class = "NSMenuItem"; title = "Reverse"; ObjectID = "xhf-NR-D2Q"; */ "xhf-NR-D2Q.title" = "Umdrehen"; +/* Class = "NSMenuItem"; title = "Delete Duplicates"; ObjectID = "bjv-m0-tZq"; */ +"bjv-m0-tZq.title" = "Doppelte löschen"; /* Class = "NSMenuItem"; title = "Delete Line"; ObjectID = "sFn-3j-pY5"; */ "sFn-3j-pY5.title" = "Zeile löschen"; diff --git a/CotEditor/ja.lproj/Localizable.strings b/CotEditor/ja.lproj/Localizable.strings index d582bd52d..31d193fc7 100644 --- a/CotEditor/ja.lproj/Localizable.strings +++ b/CotEditor/ja.lproj/Localizable.strings @@ -187,6 +187,7 @@ "Move Line" = "行を移動"; "Sort Lines" = "行をソート"; "Reverse Lines" = "行を反転"; +"Remove Duplicate Lines" = "重複行を削除"; "Delete Line" = "行を削除"; // Menu items diff --git a/CotEditor/ja.lproj/MainMenu.strings b/CotEditor/ja.lproj/MainMenu.strings index ef21ad54b..31e601f62 100644 --- a/CotEditor/ja.lproj/MainMenu.strings +++ b/CotEditor/ja.lproj/MainMenu.strings @@ -327,6 +327,8 @@ "OQl-Uo-yfn.title" = "ソート"; /* Class = "NSMenuItem"; title = "Reverse"; ObjectID = "xhf-NR-D2Q"; */ "xhf-NR-D2Q.title" = "反転"; +/* Class = "NSMenuItem"; title = "Delete Duplicates"; ObjectID = "bjv-m0-tZq"; */ +"bjv-m0-tZq.title" = "重複を削除"; /* Class = "NSMenuItem"; title = "Delete Line"; ObjectID = "sFn-3j-pY5"; */ "sFn-3j-pY5.title" = "行を削除"; diff --git a/CotEditor/zh-Hans.lproj/Localizable.strings b/CotEditor/zh-Hans.lproj/Localizable.strings index eaf93a290..9799fc243 100644 --- a/CotEditor/zh-Hans.lproj/Localizable.strings +++ b/CotEditor/zh-Hans.lproj/Localizable.strings @@ -184,6 +184,7 @@ "Move Line" = "Move Line"; // FIXME: added "Sort Lines" = "Sort Lines"; // FIXME: added "Reverse Lines" = "Reverse Lines"; // FIXME: added +"Remove Duplicate Lines" = "Remove Duplicate Lines"; // FIXME: added "Delete Line" = "Delete Line"; // FIXME: added // Menu items diff --git a/CotEditor/zh-Hans.lproj/MainMenu.strings b/CotEditor/zh-Hans.lproj/MainMenu.strings index 3aaf597af..9a02de036 100644 --- a/CotEditor/zh-Hans.lproj/MainMenu.strings +++ b/CotEditor/zh-Hans.lproj/MainMenu.strings @@ -328,6 +328,8 @@ "OQl-Uo-yfn.title" = "Sort"; // FIXME: added /* Class = "NSMenuItem"; title = "Reverse"; ObjectID = "xhf-NR-D2Q"; */ "xhf-NR-D2Q.title" = "Reverse"; // FIXME: added +/* Class = "NSMenuItem"; title = "Delete Duplicates"; ObjectID = "bjv-m0-tZq"; */ +"bjv-m0-tZq.title" = "Delete Duplicates"; // FIXME: added /* Class = "NSMenuItem"; title = "Delete Line"; ObjectID = "sFn-3j-pY5"; */ "sFn-3j-pY5.title" = "Delete Line"; // FIXME: added