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

Allow Project Find Results to be copied to clipboard #764

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion lib/project-find-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ class ProjectFindView {
'find-and-replace:use-selection-as-find-pattern': () => this.setSelectionAsFindPattern()
}));

this.subscriptions.add(atom.commands.add('.preview-pane', {
'project-find:copy-search-results': this.copySearchResultFromPane
}));

this.subscriptions.add(atom.commands.add(this.element, {
'find-and-replace:focus-next': () => this.focusNextElement(1),
'find-and-replace:focus-previous': () => this.focusNextElement(-1),
Expand All @@ -188,7 +192,8 @@ class ProjectFindView {
'project-find:toggle-regex-option': () => this.toggleRegexOption(),
'project-find:toggle-case-option': () => this.toggleCaseOption(),
'project-find:toggle-whole-word-option': () => this.toggleWholeWordOption(),
'project-find:replace-all': () => this.replaceAll()
'project-find:replace-all': () => this.replaceAll(),
'project-find:copy-search-results': () => this.copySearchResultFromPane()
}));

let updateInterfaceForSearching = () => {
Expand Down Expand Up @@ -235,6 +240,11 @@ class ProjectFindView {
this.handleEventsForReplace();
}

copySearchResultFromPane() {
atom.clipboard.write(Util.parseSearchResult());
atom.notifications.addInfo('Search results have been copied to clipboard');
}

handleEventsForReplace() {
this.replaceEditor.getBuffer().onDidChange(() => this.model.clearReplacementState());
this.replaceEditor.onDidStopChanging(() => this.model.getFindOptions().set({replacePattern: this.replaceEditor.getText()}));
Expand Down
24 changes: 23 additions & 1 deletion lib/project/util.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,29 @@ showIf = (condition) ->
else
{display: 'none'}

parseSearchResult = ->
searchResult = []
summary = document.querySelector('span.preview-count').textContent
searchResult.push summary, ''

orderList = document.querySelectorAll('.results-view ol.list-tree.has-collapsable-children')
orderListArray = Array.prototype.slice.call(orderList) # only visible item shown in DOM, you cannot query all search results
resItems = orderListArray[1].querySelectorAll('div > li') # omit first element which is dummy

resItems.forEach (el) ->
path = el.querySelector('div > span.path-name').textContent
matches = el.querySelector('div > span.path-match-number').textContent
searchResult.push "#{path} #{matches}"

el.querySelectorAll('li.search-result').forEach (e) ->
return if e.offsetParent is null # skip invisible elements
lineNumber = e.querySelector('span.line-number').textContent
preview = e.querySelector('span.preview').textContent
searchResult.push "\t#{lineNumber}\t#{preview}"
searchResult.push ''
searchResult.join('\n')

module.exports = {
escapeHtml, escapeRegex, sanitizePattern, getReplacementResultsMessage,
getSearchResultsMessage, showIf
getSearchResultsMessage, showIf, parseSearchResult
}
3 changes: 3 additions & 0 deletions menus/find-and-replace.cson
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@
'.path-details.list-item': [
{ 'label': 'Copy Path', 'command': 'find-and-replace:copy-path' }
]
'div.preview-pane': [
{ 'label': 'Copy to Clipboard', 'command': 'project-find:copy-search-results' }
]
20 changes: 19 additions & 1 deletion spec/project-find-view-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,24 @@ describe('ProjectFindView', () => {
expect(projectFindView.errorMessages).not.toBeVisible();
});

it("can copy search results to clipboard", async () => {
oldClipboardText = atom.clipboard.read();

atom.commands.dispatch(projectFindView.element, 'core:confirm');
await searchPromise;

const resultsView = getResultsView();
await resultsView.heightInvalidationPromise;

atom.commands.dispatch(resultsView.element, 'project-find:copy-search-results');
searchResults = atom.clipboard.read().split('\n');
expect(searchResults[0]).toBe("13 results found in 2 files for items");
expect(searchResults[2]).toBe("sample.coffee (7 matches)");
expect(searchResults[3]).toBe("\t2\tsort: (items) ->");
expect(searchResults[4]).toBe("\t3\treturn items if items.length <= 1");
atom.clipboard.write(oldClipboardText);
});

it("only searches paths matching text in the path filter", async () => {
spyOn(atom.workspace, 'scan').andCallFake(async () => {});
projectFindView.pathsEditor.setText('*.js');
Expand Down Expand Up @@ -1508,4 +1526,4 @@ function simulateResizeEvent(element) {
child.dispatchEvent(new AnimationEvent('animationstart'));
});
advanceClock(1);
}
}