Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit 4841893

Browse files
committed
🎨 copy search result of project-find to clipboard
- add parseSearchResult() in util.coffee with DOM api - add copySearchResultFromPane() in project-find-view.js - add spec in project-find-view-spec.js - add context-menu item
1 parent 3ea44d7 commit 4841893

File tree

4 files changed

+56
-3
lines changed

4 files changed

+56
-3
lines changed

lib/project-find-view.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ class ProjectFindView {
178178
'find-and-replace:use-selection-as-find-pattern': () => this.setSelectionAsFindPattern()
179179
}));
180180

181+
this.subscriptions.add(atom.commands.add('.preview-pane', {
182+
'project-find:copy-search-results': this.copySearchResultFromPane
183+
}));
184+
181185
this.subscriptions.add(atom.commands.add(this.element, {
182186
'find-and-replace:focus-next': () => this.focusNextElement(1),
183187
'find-and-replace:focus-previous': () => this.focusNextElement(-1),
@@ -188,7 +192,8 @@ class ProjectFindView {
188192
'project-find:toggle-regex-option': () => this.toggleRegexOption(),
189193
'project-find:toggle-case-option': () => this.toggleCaseOption(),
190194
'project-find:toggle-whole-word-option': () => this.toggleWholeWordOption(),
191-
'project-find:replace-all': () => this.replaceAll()
195+
'project-find:replace-all': () => this.replaceAll(),
196+
'project-find:copy-search-results': () => this.copySearchResultFromPane()
192197
}));
193198

194199
let updateInterfaceForSearching = () => {
@@ -235,6 +240,11 @@ class ProjectFindView {
235240
this.handleEventsForReplace();
236241
}
237242

243+
copySearchResultFromPane() {
244+
atom.clipboard.write(Util.parseSearchResult());
245+
atom.notifications.addInfo('Search results have been copied to clipboard');
246+
}
247+
238248
handleEventsForReplace() {
239249
this.replaceEditor.getBuffer().onDidChange(() => this.model.clearReplacementState());
240250
this.replaceEditor.onDidStopChanging(() => this.model.getFindOptions().set({replacePattern: this.replaceEditor.getText()}));

lib/project/util.coffee

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,29 @@ showIf = (condition) ->
3636
else
3737
{display: 'none'}
3838

39+
parseSearchResult = ->
40+
searchResult = []
41+
summary = document.querySelector('span.preview-count').textContent
42+
searchResult.push summary, ''
43+
44+
orderList = document.querySelectorAll('.results-view ol.list-tree.has-collapsable-children')
45+
orderListArray = Array.prototype.slice.call(orderList) # only visible item shown in DOM, you cannot query all search results
46+
resItems = orderListArray[1].querySelectorAll('div > li') # omit first element which is dummy
47+
48+
resItems.forEach (el) ->
49+
path = el.querySelector('div > span.path-name').textContent
50+
matches = el.querySelector('div > span.path-match-number').textContent
51+
searchResult.push "#{path} #{matches}"
52+
53+
el.querySelectorAll('li.search-result').forEach (e) ->
54+
return if e.offsetParent is null # skip invisible elements
55+
lineNumber = e.querySelector('span.line-number').textContent
56+
preview = e.querySelector('span.preview').textContent
57+
searchResult.push "\t#{lineNumber}\t#{preview}"
58+
searchResult.push ''
59+
searchResult.join('\n')
60+
3961
module.exports = {
4062
escapeHtml, escapeRegex, sanitizePattern, getReplacementResultsMessage,
41-
getSearchResultsMessage, showIf
63+
getSearchResultsMessage, showIf, parseSearchResult
4264
}

menus/find-and-replace.cson

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@
2828
'.path-details.list-item': [
2929
{ 'label': 'Copy Path', 'command': 'find-and-replace:copy-path' }
3030
]
31+
'div.preview-pane': [
32+
{ 'label': 'Copy to Clipboard', 'command': 'project-find:copy-search-results' }
33+
]

spec/project-find-view-spec.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,24 @@ describe('ProjectFindView', () => {
724724
expect(projectFindView.errorMessages).not.toBeVisible();
725725
});
726726

727+
it("can copy search results to clipboard", async () => {
728+
oldClipboardText = atom.clipboard.read();
729+
730+
atom.commands.dispatch(projectFindView.element, 'core:confirm');
731+
await searchPromise;
732+
733+
const resultsView = getResultsView();
734+
await resultsView.heightInvalidationPromise;
735+
736+
atom.commands.dispatch(resultsView.element, 'project-find:copy-search-results');
737+
searchResults = atom.clipboard.read().split('\n');
738+
expect(searchResults[0]).toBe("13 results found in 2 files for items");
739+
expect(searchResults[2]).toBe("sample.coffee (7 matches)");
740+
expect(searchResults[3]).toBe("\t2\tsort: (items) ->");
741+
expect(searchResults[4]).toBe("\t3\treturn items if items.length <= 1");
742+
atom.clipboard.write(oldClipboardText);
743+
});
744+
727745
it("only searches paths matching text in the path filter", async () => {
728746
spyOn(atom.workspace, 'scan').andCallFake(async () => {});
729747
projectFindView.pathsEditor.setText('*.js');
@@ -1508,4 +1526,4 @@ function simulateResizeEvent(element) {
15081526
child.dispatchEvent(new AnimationEvent('animationstart'));
15091527
});
15101528
advanceClock(1);
1511-
}
1529+
}

0 commit comments

Comments
 (0)