From b229dd21f4194dff00b9e6e56a91801637889dee Mon Sep 17 00:00:00 2001 From: Derek Greentree Date: Thu, 17 Jan 2013 15:36:22 -0800 Subject: [PATCH] fuzzy find files using content under cursor --- src/app/buffer.coffee | 1 + src/app/cursor.coffee | 12 +++++- .../fuzzy-finder/keymaps/fuzzy-finder.cson | 1 + .../spec/fuzzy-finder-spec.coffee | 34 +++++++++++++++ .../fuzzy-finder/src/fuzzy-finder.coffee | 41 +++++++++++++++++-- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 59c6bdd21..b8a08e580 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -288,6 +288,7 @@ class Buffer matchesInCharacterRange: (regex, startIndex, endIndex) -> text = @getText() + matches = [] regex.lastIndex = startIndex diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index 498b2ef83..336be0c53 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -150,7 +150,7 @@ class Cursor previousLinesRange = [[previousNonBlankRow, 0], currentBufferPosition] beginningOfWordPosition = currentBufferPosition - @editSession.backwardsScanInRange @wordRegex, previousLinesRange, (match, matchRange, { stop }) => + @editSession.backwardsScanInRange (options.wordRegex || @wordRegex), previousLinesRange, (match, matchRange, { stop }) => if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious beginningOfWordPosition = matchRange.start stop() @@ -162,7 +162,7 @@ class Cursor range = [currentBufferPosition, @editSession.getEofBufferPosition()] endOfWordPosition = null - @editSession.scanInRange @wordRegex, range, (match, matchRange, { stop }) => + @editSession.scanInRange (options.wordRegex || @wordRegex), range, (match, matchRange, { stop }) => endOfWordPosition = matchRange.end if not allowNext and matchRange.start.isGreaterThan(currentBufferPosition) endOfWordPosition = currentBufferPosition @@ -195,6 +195,14 @@ class Cursor getCurrentWordPrefix: -> @editSession.getTextInBufferRange([@getBeginningOfCurrentWordBufferPosition(), @getBufferPosition()]) + getCurrentWord: (options = {}) -> + match = @editSession.getTextInBufferRange([@getBeginningOfCurrentWordBufferPosition(options), + @getEndOfCurrentWordBufferPosition(options)]) + return match if options.includeDelimiter? + + if match?.length > 2 + match.substring(1, match.length-1) + isAtBeginningOfLine: -> @getBufferPosition().column == 0 diff --git a/src/packages/fuzzy-finder/keymaps/fuzzy-finder.cson b/src/packages/fuzzy-finder/keymaps/fuzzy-finder.cson index fca322bed..c4267c9e2 100644 --- a/src/packages/fuzzy-finder/keymaps/fuzzy-finder.cson +++ b/src/packages/fuzzy-finder/keymaps/fuzzy-finder.cson @@ -1,3 +1,4 @@ 'body': 'meta-t': 'fuzzy-finder:toggle-file-finder' 'meta-b': 'fuzzy-finder:toggle-buffer-finder' + 'ctrl-.': 'fuzzy-finder:find-under-cursor' diff --git a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee index 4453b2602..f19ca662f 100644 --- a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee +++ b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee @@ -270,6 +270,40 @@ describe 'FuzzyFinder', -> runs -> expect(finder.list.find("li:contains(tree-view.js)")).not.toExist() + describe "fuzzy find by content under cursor", -> + beforeEach -> + rootView.attachToDom() + spyOn(rootView.project, "getFilePaths").andCallThrough() + + it "opens the fuzzy finder window when there are multiple matches", -> + cursor = rootView.getActiveEditor().getCursor() + spyOn(cursor, "getCurrentWord").andReturn("sample") + rootView.trigger 'fuzzy-finder:find-under-cursor' + + waitsFor -> + finder.list.children('li').length > 0 + + runs -> + expect(rootView.find('.fuzzy-finder')).toExist() + expect(rootView.find('.fuzzy-finder input:focus')).toExist() + + it "opens a file directly when there is a single match", -> + cursor = rootView.getActiveEditor().getCursor() + spyOn(cursor, "getCurrentWord").andReturn("sample.txt") + + openedPath = null + spyOn(rootView, "open").andCallFake (path) -> + openedPath = path + + rootView.trigger 'fuzzy-finder:find-under-cursor' + + waitsFor -> + openedPath != null + + runs -> + expect(rootView.find('.fuzzy-finder')).not.toExist() + expect(openedPath).toBe "sample.txt" + describe "opening a path into a split", -> beforeEach -> rootView.attachToDom() diff --git a/src/packages/fuzzy-finder/src/fuzzy-finder.coffee b/src/packages/fuzzy-finder/src/fuzzy-finder.coffee index 44a9aa17a..d67ce7985 100644 --- a/src/packages/fuzzy-finder/src/fuzzy-finder.coffee +++ b/src/packages/fuzzy-finder/src/fuzzy-finder.coffee @@ -6,10 +6,13 @@ fs = require 'fs' module.exports = class FuzzyFinder extends SelectList + filenameRegex: /([^\w\.\-\/\\])/ + @activate: (rootView) -> @instance = new FuzzyFinder(rootView) rootView.command 'fuzzy-finder:toggle-file-finder', => @instance.toggleFileFinder() rootView.command 'fuzzy-finder:toggle-buffer-finder', => @instance.toggleBufferFinder() + rootView.command 'fuzzy-finder:find-under-cursor', => @instance.findUnderCursor() @viewClass: -> [super, 'fuzzy-finder'].join(' ') @@ -93,9 +96,32 @@ class FuzzyFinder extends SelectList @populateOpenBufferPaths() @attach() if @paths?.length - populateProjectPaths: -> + findUnderCursor: -> + if @hasParent() + @cancel() + else + return unless @rootView.project.getPath()? + @allowActiveEditorChange = false + theWord = @rootView.getActiveEditor() + .getCursor().getCurrentWord(wordRegex: @filenameRegex) + if theWord? + @populateProjectPaths(filter: theWord, done: (paths) => + if paths?.length == 1 + @rootView.open(paths[0]) + else + @attach() if paths?.length + @miniEditor.setText(theWord)) + + populateProjectPaths: (options = {}) -> if @projectPaths?.length > 0 - @setArray(@projectPaths) + listedItems = + if options.filter? + @projectPaths.filter (path) -> + return path.indexOf(options.filter) >= 0 + else + @projectPaths + @setArray(listedItems) + options.done(listedItems) if options.done? else @setLoading("Indexing...") @@ -111,7 +137,16 @@ class FuzzyFinder extends SelectList return true @reloadProjectPaths = false - @setArray(@projectPaths) + listedItems = + if options.filter? + @projectPaths.filter (path) -> + return path.indexOf(options.filter) >= 0 + else + @projectPaths + + @setArray(listedItems) + debugger + options.done(listedItems) if options.done? populateOpenBufferPaths: -> @paths = @rootView.getOpenBufferPaths().map (path) =>