From 25378e9905916281d738cb53a8231fe67a65b240 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 13 Aug 2013 11:58:04 -0700 Subject: [PATCH] Pull out command-panel package into a separate repo --- package.json | 1 + .../command-panel/keymaps/command-panel.cson | 24 - .../lib/command-interpreter.coffee | 23 - .../lib/command-panel-view.coffee | 186 ------ .../command-panel/lib/command-panel.coffee | 14 - src/packages/command-panel/lib/commands.pegjs | 67 -- .../lib/commands/address-range.coffee | 12 - .../command-panel/lib/commands/address.coffee | 21 - .../command-panel/lib/commands/command.coffee | 7 - .../lib/commands/composite-command.coffee | 62 -- .../commands/current-selection-address.coffee | 8 - .../lib/commands/default-address-range.coffee | 11 - .../lib/commands/eof-address.coffee | 10 - .../lib/commands/line-address.coffee | 12 - .../lib/commands/regex-address.coffee | 47 -- .../select-all-matches-in-project.coffee | 24 - .../lib/commands/select-all-matches.coffee | 23 - .../lib/commands/substitution.coffee | 28 - .../lib/commands/zero-address.coffee | 9 - .../command-panel/lib/operation-view.coffee | 33 - .../command-panel/lib/operation.coffee | 36 -- .../command-panel/lib/path-view.coffee | 60 -- .../command-panel/lib/preview-list.coffee | 133 ---- src/packages/command-panel/package.cson | 11 - .../spec/command-interpreter-spec.coffee | 465 -------------- .../spec/command-panel-spec.coffee | 597 ------------------ .../spec/preview-list-spec.coffee | 67 -- .../stylesheets/command-panel.less | 151 ----- 28 files changed, 1 insertion(+), 2141 deletions(-) delete mode 100644 src/packages/command-panel/keymaps/command-panel.cson delete mode 100644 src/packages/command-panel/lib/command-interpreter.coffee delete mode 100644 src/packages/command-panel/lib/command-panel-view.coffee delete mode 100644 src/packages/command-panel/lib/command-panel.coffee delete mode 100644 src/packages/command-panel/lib/commands.pegjs delete mode 100644 src/packages/command-panel/lib/commands/address-range.coffee delete mode 100644 src/packages/command-panel/lib/commands/address.coffee delete mode 100644 src/packages/command-panel/lib/commands/command.coffee delete mode 100644 src/packages/command-panel/lib/commands/composite-command.coffee delete mode 100644 src/packages/command-panel/lib/commands/current-selection-address.coffee delete mode 100644 src/packages/command-panel/lib/commands/default-address-range.coffee delete mode 100644 src/packages/command-panel/lib/commands/eof-address.coffee delete mode 100644 src/packages/command-panel/lib/commands/line-address.coffee delete mode 100644 src/packages/command-panel/lib/commands/regex-address.coffee delete mode 100644 src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee delete mode 100644 src/packages/command-panel/lib/commands/select-all-matches.coffee delete mode 100644 src/packages/command-panel/lib/commands/substitution.coffee delete mode 100644 src/packages/command-panel/lib/commands/zero-address.coffee delete mode 100644 src/packages/command-panel/lib/operation-view.coffee delete mode 100644 src/packages/command-panel/lib/operation.coffee delete mode 100644 src/packages/command-panel/lib/path-view.coffee delete mode 100644 src/packages/command-panel/lib/preview-list.coffee delete mode 100644 src/packages/command-panel/package.cson delete mode 100644 src/packages/command-panel/spec/command-interpreter-spec.coffee delete mode 100644 src/packages/command-panel/spec/command-panel-spec.coffee delete mode 100644 src/packages/command-panel/spec/preview-list-spec.coffee delete mode 100644 src/packages/command-panel/stylesheets/command-panel.less diff --git a/package.json b/package.json index 41f963002..9a7cb654c 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "bookmarks": "0.1.0", "bracket-matcher": "0.1.0", "command-logger": "0.1.0", + "command-panel": "0.1.0", "command-palette": "0.1.0", "fuzzy-finder": "0.1.0", "editor-stats": "0.1.0", diff --git a/src/packages/command-panel/keymaps/command-panel.cson b/src/packages/command-panel/keymaps/command-panel.cson deleted file mode 100644 index 8fb5a304e..000000000 --- a/src/packages/command-panel/keymaps/command-panel.cson +++ /dev/null @@ -1,24 +0,0 @@ -'body': - 'meta-:': 'command-panel:toggle-preview' - 'meta-;': 'command-panel:toggle' - 'meta-F': 'command-panel:find-in-project' - -'.command-panel .preview-list, .command-panel .editor input': - 'enter': 'core:confirm' - -'.editor': - 'meta-g': 'command-panel:repeat-relative-address' - 'meta-G': 'command-panel:repeat-relative-address-in-reverse' - 'meta-e': 'command-panel:set-selection-as-regex-address' - 'meta-f': 'command-panel:find-in-file' - 'meta-F': 'command-panel:find-in-project' - -'.command-panel': - 'ctrl-{': 'command-panel:collapse-all' - 'ctrl-}': 'command-panel:expand-all' - -'.command-panel .preview-list': - 'left': 'command-panel:collapse-result' - 'ctrl-[': 'command-panel:collapse-result' - 'right': 'command-panel:expand-result' - 'ctrl-]': 'command-panel:expand-result' diff --git a/src/packages/command-panel/lib/command-interpreter.coffee b/src/packages/command-panel/lib/command-interpreter.coffee deleted file mode 100644 index 2432b9764..000000000 --- a/src/packages/command-panel/lib/command-interpreter.coffee +++ /dev/null @@ -1,23 +0,0 @@ -fsUtils = require 'fs-utils' -PEG = require 'pegjs' -shell = require 'shell' - -module.exports = -class CommandInterpreter - constructor: (@project) -> - - eval: (string, activeEditSession) -> - @parser ?= PEG.buildParser(fsUtils.read(require.resolve 'command-panel/lib/commands.pegjs')) - compositeCommand = @parser.parse(string) - @lastRelativeAddress = compositeCommand if compositeCommand.isRelativeAddress() - compositeCommand.execute(@project, activeEditSession) - - repeatRelativeAddress: (activeEditSession, {reverse}={}) -> - return unless @lastRelativeAddress - reverse ?= false - previousSelectionRange = activeEditSession.getSelection().getBufferRange() - address = if reverse then @lastRelativeAddress.reverse() else @lastRelativeAddress - - address.execute(@project, activeEditSession).done -> - currentSelectionRange = activeEditSession.getSelection().getBufferRange() - shell.beep() if previousSelectionRange.isEqual(currentSelectionRange) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee deleted file mode 100644 index aa6277309..000000000 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ /dev/null @@ -1,186 +0,0 @@ -{View, $$, $$$} = require 'space-pen' -CommandInterpreter = require './command-interpreter' -RegexAddress = require './commands/regex-address' -CompositeCommand = require './commands/composite-command' -PreviewList = require './preview-list' -Editor = require 'editor' -EditSession = require 'edit-session' -{SyntaxError} = require('pegjs').parser -_ = require 'underscore' - -module.exports = -class CommandPanelView extends View - @content: -> - @div class: 'command-panel tool-panel', => - @div class: 'loading is-loading', outlet: 'loadingMessage', => - @span 'Searching...' - @div class: 'header', outlet: 'previewHeader', => - @button outlet: 'collapseAll', class: 'btn btn-mini pull-right', 'Collapse All' - @button outlet: 'expandAll', class: 'btn btn-mini pull-right', 'Expand All' - @span outlet: 'previewCount', class: 'preview-count' - - @subview 'previewList', new PreviewList(rootView) - @ul class: 'error-messages', outlet: 'errorMessages' - @div class: 'prompt-and-editor', => - @div class: 'prompt', outlet: 'prompt' - @subview 'miniEditor', new Editor(mini: true) - - commandInterpreter: null - history: null - historyIndex: 0 - maxSerializedHistorySize: 100 - - initialize: (state) -> - @commandInterpreter = new CommandInterpreter(project) - - @command 'tool-panel:unfocus', => rootView.focus() - @command 'core:close', => @detach(); false - @command 'core:cancel', => @detach(); false - @command 'core:confirm', => @execute() - @command 'core:move-up', => @navigateBackwardInHistory() - @command 'core:move-down', => @navigateForwardInHistory() - - @subscribeToCommand rootView, 'command-panel:toggle', => @toggle() - @subscribeToCommand rootView, 'command-panel:toggle-preview', => @togglePreview() - @subscribeToCommand rootView, 'command-panel:find-in-file', => @findInFile() - @subscribeToCommand rootView, 'command-panel:find-in-project', => @findInProject() - @subscribeToCommand rootView, 'command-panel:repeat-relative-address', => @repeatRelativeAddress() - @subscribeToCommand rootView, 'command-panel:repeat-relative-address-in-reverse', => @repeatRelativeAddress(reverse: true) - @subscribeToCommand rootView, 'command-panel:set-selection-as-regex-address', => @setSelectionAsLastRelativeAddress() - - @expandAll.on 'click', @onExpandAll - @collapseAll.on 'click', @onCollapseAll - - @previewList.hide() - @previewHeader.hide() - @errorMessages.hide() - @loadingMessage.hide() - @prompt.iconSize(@miniEditor.getFontSize()) - - @history = state.history ? [] - @historyIndex = @history.length - - serialize: -> - text: @miniEditor.getText() - history: @history[-@maxSerializedHistorySize..] - - destroy: -> - @previewList.destroy() - @remove() - - toggle: -> - if @miniEditor.isFocused - @detach() - rootView.focus() - else - @attach() unless @hasParent() - @miniEditor.focus() - - togglePreview: -> - if @previewList.is(':focus') - @previewList.hide() - @previewHeader.hide() - @detach() - rootView.focus() - else - @attach() unless @hasParent() - if @previewList.hasOperations() - @previewList.show().focus() - @previewHeader.show() - else - @miniEditor.focus() - - onExpandAll: (event) => - @previewList.expandAllPaths() - @previewList.focus() - - onCollapseAll: (event) => - @previewList.collapseAllPaths() - @previewList.focus() - - attach: (text, options={}) -> - @errorMessages.hide() - - focus = options.focus ? true - rootView.vertical.append(this) - @miniEditor.focus() if focus - if text? - @miniEditor.setText(text) - @miniEditor.setCursorBufferPosition([0, Infinity]) - else - @miniEditor.selectAll() - - detach: -> - rootView.focus() - @previewList.hide() - @previewHeader.hide() - super - - findInFile: -> - if @miniEditor.getText()[0] is '/' - @attach() - @miniEditor.setSelectedBufferRange([[0, 1], [0, Infinity]]) - else - @attach('/') - - findInProject: -> - if @miniEditor.getText().indexOf('Xx/') is 0 - @attach() - @miniEditor.setSelectedBufferRange([[0, 3], [0, Infinity]]) - else - @attach('Xx/') - - escapedCommand: -> - @miniEditor.getText() - - execute: (command=@escapedCommand()) -> - @loadingMessage.show() - @previewList.hide() - @previewHeader.hide() - @errorMessages.empty() - - try - activePaneItem = rootView.getActivePaneItem() - editSession = activePaneItem if activePaneItem instanceof EditSession - @commandInterpreter.eval(command, editSession).done ({operationsToPreview, errorMessages}) => - @loadingMessage.hide() - @history.push(command) - @historyIndex = @history.length - - if errorMessages.length > 0 - @flashError() - @errorMessages.show() - @errorMessages.append $$ -> - @li errorMessage for errorMessage in errorMessages - else if operationsToPreview?.length - @previewHeader.show() - @previewList.populate(operationsToPreview) - @previewList.focus() - @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show() - else - @detach() - catch error - @loadingMessage.hide() - if error.name is "SyntaxError" - @flashError() - return - else - throw error - - navigateBackwardInHistory: -> - return if @historyIndex == 0 - @historyIndex-- - @miniEditor.setText(@history[@historyIndex]) - - navigateForwardInHistory: -> - return if @historyIndex == @history.length - @historyIndex++ - @miniEditor.setText(@history[@historyIndex] or '') - - repeatRelativeAddress: (options) -> - @commandInterpreter.repeatRelativeAddress(rootView.getActivePaneItem(), options) - - setSelectionAsLastRelativeAddress: -> - selection = rootView.getActiveView().getSelectedText() - regex = _.escapeRegExp(selection) - @commandInterpreter.lastRelativeAddress = new CompositeCommand([new RegexAddress(regex)]) diff --git a/src/packages/command-panel/lib/command-panel.coffee b/src/packages/command-panel/lib/command-panel.coffee deleted file mode 100644 index 43291ef80..000000000 --- a/src/packages/command-panel/lib/command-panel.coffee +++ /dev/null @@ -1,14 +0,0 @@ -CommandPanelView = require './command-panel-view' - -module.exports = - commandPanelView: null - - activate: (state) -> - @commandPanelView = new CommandPanelView(state) - - deactivate: -> - @commandPanelView?.destroy() - @commandPanelView = null - - serialize: -> - @commandPanelView.serialize() diff --git a/src/packages/command-panel/lib/commands.pegjs b/src/packages/command-panel/lib/commands.pegjs deleted file mode 100644 index 81f1b9c8e..000000000 --- a/src/packages/command-panel/lib/commands.pegjs +++ /dev/null @@ -1,67 +0,0 @@ -{ - var CompositeCommand = require('command-panel/lib/commands/composite-command') - var Substitution = require('command-panel/lib/commands/substitution'); - var ZeroAddress = require('command-panel/lib/commands/zero-address'); - var EofAddress = require('command-panel/lib/commands/eof-address'); - var LineAddress = require('command-panel/lib/commands/line-address'); - var AddressRange = require('command-panel/lib/commands/address-range'); - var DefaultAddressRange = require('command-panel/lib/commands/default-address-range'); - var CurrentSelectionAddress = require('command-panel/lib/commands/current-selection-address') - var RegexAddress = require('command-panel/lib/commands/regex-address') - var SelectAllMatches = require('command-panel/lib/commands/select-all-matches') - var SelectAllMatchesInProject = require('command-panel/lib/commands/select-all-matches-in-project') -} - -start = _ commands:( selectAllMatchesInProject / textCommand ) { - return new CompositeCommand(commands); -} - -textCommand = defaultAddress:defaultAddress? expressions:expression* { - if (defaultAddress) expressions.unshift(defaultAddress); - return expressions; -} - -defaultAddress = !address { - return new DefaultAddressRange(); -} - -expression = _ expression:(address / substitution / selectAllMatches) { - return expression; -} - -address = addressRange / primitiveAddress - -addressRange = start:primitiveAddress? _ ',' _ end:address? { - if (!start) start = new ZeroAddress(); - if (!end) end = new EofAddress(); - return new AddressRange(start, end); -} - -primitiveAddress - = '0' { return new ZeroAddress() } - / '$' { return new EofAddress() } - / '.' { return new CurrentSelectionAddress() } - / lineNumber:integer { return new LineAddress(lineNumber) } - / regexAddress - -regexAddress - = reverse:'-'? '/' pattern:pattern '/'? { return new RegexAddress(pattern, reverse.length > 0)} - -substitution - = "s" _ "/" find:pattern "/" replace:pattern "/" _ options:[g]* { - return new Substitution(find, eval("'" + replace + "'"), options); - } - -selectAllMatches - = 'x' _ '/' pattern:pattern '/'? { return new SelectAllMatches(pattern) } - -selectAllMatchesInProject - = 'X' _ 'x' _ '/' pattern:pattern '/'? { return [new SelectAllMatchesInProject(pattern)] } - -pattern - = pattern:('\\/' / [^/])* { return pattern.join('') } - -integer - = digits:[0-9]+ { return parseInt(digits.join('')); } - -_ = " "* diff --git a/src/packages/command-panel/lib/commands/address-range.coffee b/src/packages/command-panel/lib/commands/address-range.coffee deleted file mode 100644 index 8c4c976f2..000000000 --- a/src/packages/command-panel/lib/commands/address-range.coffee +++ /dev/null @@ -1,12 +0,0 @@ -Address = require 'command-panel/lib/commands/address' -Range = require 'range' - -module.exports = -class AddressRange extends Address - constructor: (@startAddress, @endAddress) -> - - getRange: (buffer, range) -> - new Range(@startAddress.getRange(buffer, range).start, @endAddress.getRange(buffer, range).end) - - isRelative: -> - @startAddress.isRelative() and @endAddress.isRelative() diff --git a/src/packages/command-panel/lib/commands/address.coffee b/src/packages/command-panel/lib/commands/address.coffee deleted file mode 100644 index ffa89f8ff..000000000 --- a/src/packages/command-panel/lib/commands/address.coffee +++ /dev/null @@ -1,21 +0,0 @@ -Command = require './command' -Operation = require 'command-panel/lib/operation' -$ = require 'jquery' - -module.exports = -class Address extends Command - compile: (project, buffer, ranges) -> - deferred = $.Deferred() - operations = ranges.map (range) => - newRange = @getRange(buffer, range) - - new Operation - project: project - buffer: buffer - bufferRange: newRange - errorMessage: @errorMessage - - deferred.resolve(operations) - deferred.promise() - - isAddress: -> true diff --git a/src/packages/command-panel/lib/commands/command.coffee b/src/packages/command-panel/lib/commands/command.coffee deleted file mode 100644 index 16a4e5a07..000000000 --- a/src/packages/command-panel/lib/commands/command.coffee +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = -class Command - isAddress: -> false - - errorMessage: null - preserveSelections: false - previewOperations: false diff --git a/src/packages/command-panel/lib/commands/composite-command.coffee b/src/packages/command-panel/lib/commands/composite-command.coffee deleted file mode 100644 index b7836ee62..000000000 --- a/src/packages/command-panel/lib/commands/composite-command.coffee +++ /dev/null @@ -1,62 +0,0 @@ -_ = require 'underscore' -$ = require 'jquery' - -module.exports = -class CompositeCommand - constructor: (@subcommands) -> - - execute: (project, editSession) -> - currentRanges = editSession?.getSelectedBufferRanges() ? [] - @executeCommands(@subcommands, project, editSession, currentRanges) - - executeCommands: (commands, project, editSession, ranges) -> - deferred = $.Deferred() - [currentCommand, remainingCommands...] = commands - - currentCommand.compile(project, editSession?.buffer, ranges).done (operations) => - if remainingCommands.length - errorMessages = @errorMessagesForOperations(operations) - nextRanges = operations.map (operation) -> operation.getBufferRange() - operations.forEach (operation) -> operation.destroy() - - @executeCommands(remainingCommands, project, editSession, nextRanges).done ({errorMessages: moreErrorMessages})-> - errorMessages.push(moreErrorMessages...) if moreErrorMessages - deferred.resolve({errorMessages}) - else - errorMessages = @errorMessagesForOperations(operations) - - if currentCommand.previewOperations - deferred.resolve({operationsToPreview: operations, errorMessages}) - else - bufferRanges = [] - errorMessages = @errorMessagesForOperations(operations) - - executeOperations = -> - for operation in operations - bufferRange = operation.execute(editSession) - bufferRanges.push(bufferRange) if bufferRange - operation.destroy() - - if bufferRanges.length and not currentCommand.preserveSelections - editSession.setSelectedBufferRanges(bufferRanges, autoscroll: true) - - operationsWillChangeBuffer = _.detect(operations, (operation) -> operation.newText?) - - if operationsWillChangeBuffer - editSession.transact(executeOperations) - else - executeOperations() - - deferred.resolve({errorMessages}) - - deferred.promise() - - errorMessagesForOperations: (operations) -> - operationsWithErrorMessages = operations.filter (operation) -> operation.errorMessage? - operationsWithErrorMessages.map (operation) -> operation.errorMessage - - reverse: -> - new CompositeCommand(@subcommands.map (command) -> command.reverse()) - - isRelativeAddress: -> - _.all(@subcommands, (command) -> command.isAddress() and command.isRelative()) diff --git a/src/packages/command-panel/lib/commands/current-selection-address.coffee b/src/packages/command-panel/lib/commands/current-selection-address.coffee deleted file mode 100644 index 2c01eb76e..000000000 --- a/src/packages/command-panel/lib/commands/current-selection-address.coffee +++ /dev/null @@ -1,8 +0,0 @@ -Address = require './address' - -module.exports = -class CurrentSelectionAddress extends Address - getRange: (buffer, range) -> - range - - isRelative: -> true diff --git a/src/packages/command-panel/lib/commands/default-address-range.coffee b/src/packages/command-panel/lib/commands/default-address-range.coffee deleted file mode 100644 index 60400b321..000000000 --- a/src/packages/command-panel/lib/commands/default-address-range.coffee +++ /dev/null @@ -1,11 +0,0 @@ -Address = require './address' - -module.exports = -class DefaultAddressRange extends Address - getRange: (buffer, range)-> - if range.isEmpty() - buffer.getRange() - else - range - - isRelative: -> false diff --git a/src/packages/command-panel/lib/commands/eof-address.coffee b/src/packages/command-panel/lib/commands/eof-address.coffee deleted file mode 100644 index aa13d6041..000000000 --- a/src/packages/command-panel/lib/commands/eof-address.coffee +++ /dev/null @@ -1,10 +0,0 @@ -Address = require './address' -Range = require 'range' - -module.exports = -class EofAddress extends Address - getRange: (buffer, range) -> - eof = buffer.getEofPosition() - new Range(eof, eof) - - isRelative: -> false diff --git a/src/packages/command-panel/lib/commands/line-address.coffee b/src/packages/command-panel/lib/commands/line-address.coffee deleted file mode 100644 index ab0f2ad92..000000000 --- a/src/packages/command-panel/lib/commands/line-address.coffee +++ /dev/null @@ -1,12 +0,0 @@ -Address = require './address' -Range = require 'range' - -module.exports = -class LineAddress extends Address - constructor: (lineNumber) -> - @row = lineNumber - 1 - - getRange: -> - new Range([@row, 0], [@row + 1, 0]) - - isRelative: -> false diff --git a/src/packages/command-panel/lib/commands/regex-address.coffee b/src/packages/command-panel/lib/commands/regex-address.coffee deleted file mode 100644 index 721d236c4..000000000 --- a/src/packages/command-panel/lib/commands/regex-address.coffee +++ /dev/null @@ -1,47 +0,0 @@ -Address = require './address' -Range = require 'range' - -module.exports = -class RegexAddress extends Address - regex: null - isReversed: false - - constructor: (@pattern, isReversed, options) -> - flags = "" - pattern = pattern.source if pattern.source - - patternContainsCapitalLetter = /(^|[^\\])[A-Z]/.test(pattern) - flags += "i" unless patternContainsCapitalLetter - @isReversed = isReversed - - @regex = new RegExp(pattern, flags) - - getRange: (buffer, range) -> - rangeBefore = new Range([0, 0], range.start) - rangeAfter = new Range(range.end, buffer.getEofPosition()) - - rangeToSearch = if @isReversed then rangeBefore else rangeAfter - - rangeToReturn = null - scanMethodName = if @isReversed then "backwardsScanInRange" else "scanInRange" - buffer[scanMethodName] @regex, rangeToSearch, ({range}) -> - rangeToReturn = range - - if not rangeToReturn - rangeToSearch = if @isReversed then rangeAfter else rangeBefore - buffer[scanMethodName] @regex, rangeToSearch, ({range}) -> - rangeToReturn = range - - if not rangeToReturn - flags = "" - flags += "i" if @regex.ignoreCase - flags += "g" if @regex.global - flags += "m" if @regex.multiline - @errorMessage = "Pattern not found /#{@regex.source}/#{flags}" - - rangeToReturn or range - - isRelative: -> true - - reverse: -> - new RegexAddress(@regex, !@isReversed) diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee deleted file mode 100644 index c9255a4fc..000000000 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ /dev/null @@ -1,24 +0,0 @@ -Command = require './command' -Operation = require 'command-panel/lib/operation' -$ = require 'jquery' - -module.exports = -class SelectAllMatchesInProject extends Command - regex: null - previewOperations: true - - constructor: (pattern) -> - @regex = new RegExp(pattern) - - compile: (project, buffer, range) -> - deferred = $.Deferred() - operations = [] - promise = project.scan @regex, ({path, range}) -> - operations.push(new Operation( - project: project - path: path - bufferRange: range - )) - - promise.done -> deferred.resolve(operations) - deferred.promise() diff --git a/src/packages/command-panel/lib/commands/select-all-matches.coffee b/src/packages/command-panel/lib/commands/select-all-matches.coffee deleted file mode 100644 index dc0eaef35..000000000 --- a/src/packages/command-panel/lib/commands/select-all-matches.coffee +++ /dev/null @@ -1,23 +0,0 @@ -Command = require './command' -Operation = require 'command-panel/lib/operation' -$ = require 'jquery' - -module.exports = -class SelectAllMatches extends Command - regex: null - - constructor: (pattern) -> - @regex = new RegExp(pattern, 'g') - - compile: (project, buffer, ranges) -> - deferred = $.Deferred() - operations = [] - for scanRange in ranges - buffer.scanInRange @regex, scanRange, ({range}) -> - operations.push(new Operation( - project: project - buffer: buffer - bufferRange: range - )) - deferred.resolve(operations) - deferred.promise() diff --git a/src/packages/command-panel/lib/commands/substitution.coffee b/src/packages/command-panel/lib/commands/substitution.coffee deleted file mode 100644 index 71a229c32..000000000 --- a/src/packages/command-panel/lib/commands/substitution.coffee +++ /dev/null @@ -1,28 +0,0 @@ -Command = require './command' -Operation = require 'command-panel/lib/operation' -$ = require 'jquery' - -module.exports = -class Substitution extends Command - regex: null - replacementText: null - preserveSelections: true - - constructor: (pattern, replacementText, options) -> - @replacementText = replacementText - @regex = new RegExp(pattern, options.join('')) - - compile: (project, buffer, ranges) -> - deferred = $.Deferred() - operations = [] - for scanRange in ranges - buffer.scanInRange @regex, scanRange, ({range}) => - operations.push(new Operation( - project: project - buffer: buffer - bufferRange: range - newText: @replacementText - preserveSelection: true - )) - deferred.resolve(operations) - deferred.promise() diff --git a/src/packages/command-panel/lib/commands/zero-address.coffee b/src/packages/command-panel/lib/commands/zero-address.coffee deleted file mode 100644 index 80928b29b..000000000 --- a/src/packages/command-panel/lib/commands/zero-address.coffee +++ /dev/null @@ -1,9 +0,0 @@ -Address = require './address' -Range = require 'range' - -module.exports = -class ZeroAddress extends Address - getRange: -> - new Range([0, 0], [0, 0]) - - isRelative: -> false diff --git a/src/packages/command-panel/lib/operation-view.coffee b/src/packages/command-panel/lib/operation-view.coffee deleted file mode 100644 index 666aa8836..000000000 --- a/src/packages/command-panel/lib/operation-view.coffee +++ /dev/null @@ -1,33 +0,0 @@ -{View} = require 'space-pen' - -module.exports = -class OperationView extends View - @content: ({operation} = {}) -> - {prefix, suffix, match, range} = operation.preview() - @li class: 'operation', => - @span range.start.row + 1, class: 'line-number' - @span class: 'preview', => - @span prefix - @span match, class: 'match' - @span suffix - - initialize: ({@previewList, @operation}) -> - @subscribe @previewList, 'core:confirm', => - if @hasClass('selected') - @executeOperation() - false - @on 'mousedown', (e) => - @executeOperation() - @previewList.find('.selected').removeClass('selected') - @addClass('selected') - - executeOperation: -> - editSession = rootView.open(@operation.getPath()) - bufferRange = @operation.execute(editSession) - editSession.setSelectedBufferRange(bufferRange, autoscroll: true) if bufferRange - @previewList.focus() - - scrollTo: -> - top = @previewList.scrollTop() + @offset().top - @previewList.offset().top - bottom = top + @outerHeight() - @previewList.scrollTo(top, bottom) diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee deleted file mode 100644 index c28b16f29..000000000 --- a/src/packages/command-panel/lib/operation.coffee +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = -class Operation - constructor: ({@project, @path, @buffer, @bufferRange, @newText, @preserveSelection, @errorMessage}) -> - if @buffer? - @buffer.retain() - @getMarker() - - getMarker: -> - @marker ?= @getBuffer().markRange(@bufferRange) - - getBuffer: -> - @buffer ?= @project.bufferForPath(@path).retain() - - getPath: -> - path = @path ? @getBuffer().getPath() - @project.relativize(path) - - getBufferRange: -> - @getMarker().getRange() - - execute: (editSession) -> - @getBuffer().change(@getBufferRange(), @newText) if @newText? - @getBufferRange() unless @preserveSelection - - preview: -> - range = @getBufferRange() - line = @getBuffer().lineForRow(range.start.row) - prefix = line[0...range.start.column] - match = line[range.start.column...range.end.column] - suffix = line[range.end.column..] - - {prefix, suffix, match, range} - - destroy: -> - @marker?.destroy() - @buffer?.release() diff --git a/src/packages/command-panel/lib/path-view.coffee b/src/packages/command-panel/lib/path-view.coffee deleted file mode 100644 index 7a74eeb85..000000000 --- a/src/packages/command-panel/lib/path-view.coffee +++ /dev/null @@ -1,60 +0,0 @@ -{View} = require 'space-pen' -fsUtils = require 'fs-utils' -OperationView = require './operation-view' -$ = require 'jquery' - -module.exports = -class PathView extends View - @content: ({path, previewList} = {}) -> - classes = ['path'] - classes.push('readme') if fsUtils.isReadmePath(path) - @li class: classes.join(' '), => - @div outlet: 'pathDetails', class: 'path-details', => - @span class: 'path-name', path - @span outlet: 'description', class: 'path-match-number' - @ul outlet: 'matches', class: 'matches', => - - initialize: ({@previewList, operationCount}) -> - @pathDetails.on 'mousedown', => @toggle(true) - @subscribe @previewList, 'command-panel:collapse-result', => - if @isSelected() - @collapse() - @previewList.renderOperations() - @subscribe @previewList, 'command-panel:expand-result', => - @expand() if @isSelected() - @subscribe @previewList, 'core:confirm', => - if @hasClass('selected') - @toggle(true) - false - - @description.text("(#{operationCount})") - - addOperation: (operation) -> - @matches.append new OperationView({operation, @previewList}) - - isSelected: -> - @hasClass('selected') or @find('.selected').length - - setSelected: -> - @previewList.find('.selected').removeClass('selected') - @addClass('selected') - - toggle: -> - if @hasClass('is-collapsed') - @expand() - else - @collapse() - - expand: -> - @matches.show() - @removeClass 'is-collapsed' - - scrollTo: -> - top = @previewList.scrollTop() + @offset().top - @previewList.offset().top - bottom = top + @pathDetails.outerHeight() - @previewList.scrollTo(top, bottom) - - collapse: -> - @matches.hide() - @addClass 'is-collapsed' - @setSelected() if @isSelected() diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee deleted file mode 100644 index 09faa3b96..000000000 --- a/src/packages/command-panel/lib/preview-list.coffee +++ /dev/null @@ -1,133 +0,0 @@ -$ = require 'jquery' -ScrollView = require 'scroll-view' -_ = require 'underscore' -PathView = require './path-view' -OperationView = require './operation-view' - -module.exports = -class PreviewList extends ScrollView - @content: -> - @ol class: 'preview-list', tabindex: -1 - - operations: null - viewsForPath: null - pixelOverdraw: 100 - lastRenderedOperationIndex: null - - initialize: -> - super - - @on 'core:move-down', => @selectNextOperation(); false - @on 'core:move-up', => @selectPreviousOperation(); false - @on 'scroll', => - @renderOperations() if @scrollBottom() >= @prop('scrollHeight') - @command 'command-panel:collapse-all', => @collapseAllPaths() - @command 'command-panel:expand-all', => @expandAllPaths() - - expandAllPaths: -> - @children().each (index, element) -> $(element).view().expand() - - collapseAllPaths: -> - @renderOperations(renderAll: true) - @children().each (index, element) -> $(element).view().collapse() - - destroy: -> - @destroyOperations() if @operations - - hasOperations: -> @operations? - - populate: (operations) -> - @destroyOperations() if @operations - @operations = operations - @lastRenderedOperationIndex = 0 - @empty() - @viewsForPath = {} - - @show() - @renderOperations() - - @find('.operation:first').addClass('selected') - - renderOperations: ({renderAll}={}) -> - renderAll ?= false - startingScrollHeight = @prop('scrollHeight') - for operation in @operations[@lastRenderedOperationIndex..] - pathView = @pathViewForPath(operation.getPath()) - pathView.addOperation(operation) - @lastRenderedOperationIndex++ - break if not renderAll and @prop('scrollHeight') >= startingScrollHeight + @pixelOverdraw and @prop('scrollHeight') > @height() + @pixelOverdraw - - pathViewForPath: (path) -> - pathView = @viewsForPath[path] - if not pathView - pathView = new PathView({path: path, previewList: this, operationCount: @getPathOperationCount(path)}) - @viewsForPath[path] = pathView - @append(pathView) - pathView - - selectNextOperation: -> - selectedView = @find('.selected').view() - nextView = selectedView.next().view() - - if selectedView instanceof PathView - nextView = selectedView.find('.operation:first').view() unless selectedView.hasClass('is-collapsed') - else - nextView ?= selectedView.closest('.path').next().view() - - if nextView? - selectedView.removeClass('selected') - nextView.addClass('selected') - nextView.scrollTo() - - selectPreviousOperation: -> - selectedView = @find('.selected').view() - previousView = selectedView.prev().view() - - if selectedView instanceof PathView - if previousView? and not previousView.hasClass('is-collapsed') - previousView = previousView.find('.operation:last').view() - else - previousView ?= selectedView.closest('.path').view() - - if previousView? - selectedView.removeClass('selected') - previousView.addClass('selected') - previousView.scrollTo() - - getPathCount: -> - _.keys(_.groupBy(@operations, (operation) -> operation.getPath())).length - - getPathOperationCount: (path) -> - @operations.filter((operation) -> path is operation.getPath()).length - - getOperations: -> - new Array(@operations...) - - destroyOperations: -> - operation.destroy() for operation in @getOperations() - @operations = null - - getSelectedOperation: -> - @find('.operation.selected').view()?.operation - - scrollTo: (top, bottom) -> - @scrollBottom(bottom) if bottom > @scrollBottom() - @scrollTop(top) if top < @scrollTop() - - scrollToBottom: -> - @renderOperations(renderAll: true) - - super() - - @find('.selected').removeClass('selected') - lastPath = @find('.path:last') - if lastPath.hasClass('is-collapsed') - lastPath.addClass('selected') - else - lastPath.find('.operation:last').addClass('selected') - - scrollToTop: -> - super() - - @find('.selected').removeClass('selected') - @find('.path:first').addClass('selected') diff --git a/src/packages/command-panel/package.cson b/src/packages/command-panel/package.cson deleted file mode 100644 index cc69257e2..000000000 --- a/src/packages/command-panel/package.cson +++ /dev/null @@ -1,11 +0,0 @@ -'main': './lib/command-panel' -'description': 'Find and replace text for the current editor or project.' -'activationEvents': [ - 'command-panel:toggle' - 'command-panel:toggle-preview' - 'command-panel:find-in-file' - 'command-panel:find-in-project' - 'command-panel:repeat-relative-address' - 'command-panel:repeat-relative-address-in-reverse' - 'command-panel:set-selection-as-regex-address' -] diff --git a/src/packages/command-panel/spec/command-interpreter-spec.coffee b/src/packages/command-panel/spec/command-interpreter-spec.coffee deleted file mode 100644 index acb8f8f24..000000000 --- a/src/packages/command-panel/spec/command-interpreter-spec.coffee +++ /dev/null @@ -1,465 +0,0 @@ -CommandInterpreter = require 'command-panel/lib/command-interpreter' -Project = require 'project' -Buffer = require 'text-buffer' -EditSession = require 'edit-session' - -_ = require 'underscore' - -describe "CommandInterpreter", -> - [interpreter, editSession, buffer] = [] - - beforeEach -> - interpreter = new CommandInterpreter(project) - editSession = project.open('sample.js') - buffer = editSession.buffer - - afterEach -> - editSession?.destroy() - expect(buffer.getMarkerCount()).toBe 0 - - describe "addresses", -> - beforeEach -> - editSession.addSelectionForBufferRange([[7,0], [7,11]]) - editSession.addSelectionForBufferRange([[8,0], [8,11]]) - - describe "a line address", -> - it "selects the specified line", -> - waitsForPromise -> interpreter.eval('4', editSession) - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [4, 0]] - - describe "0", -> - it "selects the zero-length string at the start of the file", -> - waitsForPromise -> interpreter.eval('0', editSession) - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [0,0]] - - interpreter.eval('0,1', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [1,0]] - - describe "$", -> - it "selects EOF", -> - waitsForPromise -> interpreter.eval('$', editSession) - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[12,2], [12,2]] - - waitsForPromise -> interpreter.eval('1,$', editSession) - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [12,2]] - - describe ".", -> - describe "when a single selection", -> - it 'maintains the current selection', -> - editSession.clearSelections() - - waitsForPromise -> - editSession.setSelectedBufferRange([[1,1], [2,2]]) - interpreter.eval('.', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[1,1], [2,2]] - - waitsForPromise -> - editSession.setSelectedBufferRange([[1,1], [2,2]]) - interpreter.eval('.,', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[1,1], [12,2]] - - waitsForPromise -> - editSession.setSelectedBufferRange([[1,1], [2,2]]) - interpreter.eval(',.', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [2,2]] - - describe "with multiple selections", -> - it "maintains the current selections", -> - preSelections = editSession.getSelections() - expect(preSelections.length).toBe 3 - [preRange1, preRange2, preRange3] = preSelections.map (s) -> s.getScreenRange() - - waitsForPromise -> interpreter.eval('.', editSession) - - runs -> - selections = editSession.getSelections() - expect(selections.length).toBe 3 - [selection1, selection2, selection3] = selections - expect(selection1.getScreenRange()).toEqual preRange1 - expect(selection2.getScreenRange()).toEqual preRange2 - expect(selection3.getScreenRange()).toEqual preRange3 - - describe "/regex/", -> - beforeEach -> - editSession.clearSelections() - - it 'selects text matching regex after current selection', -> - waitsForPromise -> - editSession.setSelectedBufferRange([[4,16], [4,20]]) - interpreter.eval('/pivot/', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[6,16], [6,21]] - - it 'does not require the trailing slash', -> - waitsForPromise -> - editSession.setSelectedBufferRange([[4,16], [4,20]]) - interpreter.eval('/pivot', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[6,16], [6,21]] - - it "searches from the end of each selection in the buffer", -> - waitsForPromise -> - editSession.clearSelections() - editSession.setSelectedBufferRange([[4,16], [4,20]]) - editSession.addSelectionForBufferRange([[1,16], [2,20]]) - expect(editSession.getSelections().length).toBe 2 - interpreter.eval('/pivot', editSession) - - runs -> - selections = editSession.getSelections() - expect(selections.length).toBe 2 - expect(selections[0].getBufferRange()).toEqual [[3,8], [3,13]] - expect(selections[1].getBufferRange()).toEqual [[6,16], [6,21]] - - it "wraps around to the beginning of the buffer, but doesn't infinitely loop if no matches are found", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[10, 0], [10,3]]) - interpreter.eval('/pivot', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] - - waitsForPromise -> - interpreter.eval('/mike tyson', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] - - it "searches in reverse when prefixed with a -", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[6, 16], [6, 22]]) - interpreter.eval('-/pivot', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] - - it "removes folds that contain the selections", -> - waitsForPromise -> - editSession.createFold(5, 6) - editSession.createFold(10, 11) - editSession.setSelectedBufferRange([[4,16], [4,20]]) - interpreter.eval('/pivot/', editSession) - - runs -> - expect(editSession.getSelection().getBufferRange()).toEqual [[6,16], [6,21]] - expect(editSession.lineForScreenRow(5).fold).toBeUndefined() - expect(editSession.lineForScreenRow(10).fold).toBeDefined() - editSession.unfoldAll() # cleanup fold marker for after assertion - - it "is case-insentive when the pattern contains no non-escaped uppercase letters (behavior copied from vim)", -> - waitsForPromise -> - interpreter.eval('/array', editSession) - runs -> - expect(interpreter.lastRelativeAddress.subcommands[0].regex.toString()).toEqual "/array/i" - - waitsForPromise -> - interpreter.eval('/a\\Sray', editSession) - runs -> - expect(interpreter.lastRelativeAddress.subcommands[0].regex.toString()).toEqual "/a\\Sray/i" - - it "allows the regex to contain an escaped forward slash", -> - buffer.setText "hey/baby" - - waitsForPromise -> - interpreter.eval('/y\\/b/', editSession) - runs -> - expect(editSession.getSelectedText()).toBe "y/b" - - it "does not push to the undo stack (since the buffer is not modified)", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[4,16], [4,20]]) - interpreter.eval('/pivot/', editSession) - - runs -> - selectedRangeBeforeUndo = editSession.getSelection().getBufferRange() - editSession.undo() - expect(editSession.getSelection().getBufferRange()).toEqual selectedRangeBeforeUndo - - describe "when no match is found", -> - it "it returns an error messages", -> - errorMessages = null - waitsForPromise -> - interpreter.eval('/garbage!', editSession).done (results) -> { errorMessages } = results - - runs -> - expect(errorMessages.length).toBe 1 - - waitsForPromise -> - interpreter.eval('/Array', editSession) - runs -> - expect(interpreter.lastRelativeAddress.subcommands[0].regex.toString()).toEqual "/Array/" - - describe "when there is no active edit session", -> - it "returns no error messages and does not throw an error", -> - errorMessages = null - - waitsForPromise -> - interpreter.eval('/something').done (results) -> - {errorMessages} = results - - runs -> - expect(errorMessages.length).toBe 0 - - describe "address range", -> - describe "when two addresses are specified", -> - it "selects from the begining of the left address to the end of the right address", -> - waitsForPromise -> interpreter.eval('4,7', editSession) - - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [7, 0]] - - describe "when the left address is unspecified", -> - it "selects from the begining of buffer to the end of the right address", -> - waitsForPromise -> interpreter.eval(',7', editSession) - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0, 0], [7, 0]] - - describe "when the right address is unspecified", -> - it "selects from the begining of left address to the end file", -> - waitsForPromise -> interpreter.eval('4,', editSession) - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [12, 2]] - - describe "when the neither address is specified", -> - it "selects the entire file", -> - waitsForPromise -> interpreter.eval(',', editSession) - runs -> - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0, 0], [12, 2]] - - describe "x/regex/", -> - it "sets the current selection to every match of the regex in the current selection", -> - waitsForPromise -> interpreter.eval('6,7 x/current/', editSession) - - runs -> - selections = editSession.getSelections() - expect(selections.length).toBe 4 - - expect(selections[0].getBufferRange()).toEqual [[5,6], [5,13]] - expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]] - expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]] - expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]] - - describe "when there is no address range is given", -> - describe "when there is no text selection", -> - it "uses the entire file as the address range", -> - waitsForPromise -> - editSession.clearSelections() - interpreter.eval('x/return', editSession) - runs -> - expect(editSession.getSelectedBufferRanges()).toEqual [ - [[2,27],[2,33]] - [[8,4], [8,10]] - [[11,2],[11,8]] - ] - - describe "when text is selected", -> - it "uses the selection as the address range", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[2, 0], [9, 0]]) - interpreter.eval('x/return', editSession) - runs -> - expect(editSession.getSelectedBufferRanges()).toEqual [ - [[2,27],[2,33]] - [[8,4], [8,10]] - ] - - describe "when matching /$/", -> - it "matches the end of each line in the selected region", -> - waitsForPromise -> interpreter.eval('6,8 x/$/', editSession) - - runs -> - cursors = editSession.getCursors() - expect(cursors.length).toBe 3 - - expect(cursors[0].getBufferPosition()).toEqual [5, 30] - expect(cursors[1].getBufferPosition()).toEqual [6, 65] - expect(cursors[2].getBufferPosition()).toEqual [7, 5] - - describe "when text is initially selected", -> - it "loops through current selections and selects text matching the regex", -> - waitsForPromise -> - editSession.setSelectedBufferRange [[3,0], [3,62]] - editSession.addSelectionForBufferRange [[6,0], [6,65]] - interpreter.eval('x/current', editSession) - - runs -> - selections = editSession.getSelections() - expect(selections.length).toBe 4 - - expect(selections[0].getBufferRange()).toEqual [[3,31], [3,38]] - expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]] - expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]] - expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]] - - describe "substitution", -> - describe "when there is no address range is given", -> - describe "when there is no text selection", -> - it "uses the entire file as the address range", -> - waitsForPromise -> - editSession.clearSelections() - interpreter.eval('s/current/foo/g', editSession) - runs -> - expect(buffer.lineForRow(3)).toBe ' var pivot = items.shift(), foo, left = [], right = [];' - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(foo);' - - describe "when text is selected", -> - it "uses the selection as the address range", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/current/foo/g', editSession) - runs -> - expect(buffer.lineForRow(3)).toBe ' var pivot = items.shift(), current, left = [], right = [];' - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' - - describe "when not global", -> - describe "when there is a single selection", -> - it "performs a single substitution within the current selection", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/current/foo/', editSession) - runs -> - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);' - - describe "when there are multiple selections", -> - it "performs a single substitutions within each of the selections", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[5, 0], [5, 20]]) - editSession.addSelectionForBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/current/foo/', editSession) - - runs -> - expect(buffer.lineForRow(5)).toBe ' foo = items.shift();' - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);' - - describe "when global", -> - it "performs a multiple substitutions within the current selection as a batch that can be undone in a single operation", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/current/foo/g', editSession) - - runs -> - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' - buffer.undo() - expect(buffer.getText()).not.toContain('foo') - - describe "when prefixed with an address", -> - it "only makes substitutions within given lines", -> - waitsForPromise -> interpreter.eval('4,6s/ /!/g', editSession) - - runs -> - expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;' - expect(buffer.lineForRow(3)).toBe '!!!!var!pivot!=!items.shift(),!current,!left!=![],!right!=![];' - expect(buffer.lineForRow(4)).toBe '!!!!while(items.length!>!0)!{' - expect(buffer.lineForRow(5)).toBe '!!!!!!current!=!items.shift();' - expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);' - - describe "when matching $", -> - it "matches the end of each line and avoids infinitely looping on a zero-width match", -> - waitsForPromise -> interpreter.eval(',s/$/!!!/g', editSession) - runs -> - expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {!!!' - expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;!!!' - expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);!!!' - expect(buffer.lineForRow(12)).toBe '};!!!' - - describe "when matching ^", -> - it "matches the beginning of each line and avoids infinitely looping on a zero-width match", -> - waitsForPromise -> interpreter.eval(',s/^/!!!/g', editSession) - runs -> - expect(buffer.lineForRow(0)).toBe '!!!var quicksort = function () {' - expect(buffer.lineForRow(2)).toBe '!!! if (items.length <= 1) return items;' - expect(buffer.lineForRow(6)).toBe '!!! current < pivot ? left.push(current) : right.push(current);' - expect(buffer.lineForRow(12)).toBe '!!!};' - - describe "when there are multiple selections", -> - it "performs a multiple substitutions within each of the selections", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[5, 0], [5, 20]]) - editSession.addSelectionForBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/current/foo/g', editSession) - - runs -> - expect(buffer.lineForRow(5)).toBe ' foo = items.shift();' - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' - - describe "when prefixed with an address", -> - it "restores the original selections upon completion if it is the last command", -> - waitsForPromise -> - editSession.setSelectedBufferRanges([[[5, 0], [5, 20]], [[6, 0], [6, 44]]]) - interpreter.eval(',s/current/foo/g', editSession) - - runs -> - expect(editSession.getSelectedBufferRanges()).toEqual [[[5, 0], [5, 16]], [[6, 0], [6, 36]]] - - it "does nothing if there are no matches", -> - waitsForPromise -> - editSession.setSelectedBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/not-in-text/foo/', editSession) - - runs -> - expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);' - - it "properly handles escaped text in the replacement text", -> - waitsForPromise -> - interpreter.eval('s/ /\\t/g', editSession) - runs -> - expect(buffer.lineForRow(6)).toBe '\t\t\tcurrent < pivot ? left.push(current) : right.push(current);' - - it "removes matched text when an empty string is given as the replacement", -> - waitsForPromise -> - interpreter.eval('s/items//', editSession) - runs -> - expect(buffer.lineForRow(1)).toBe(' var sort = function() {') - - describe "X x/regex/", -> - it "returns selection operations for all regex matches in all the project's files", -> - editSession.destroy() - project.setPath(project.resolve('dir')) - interpreter = new CommandInterpreter(project) - - operationsToPreview = null - waitsForPromise -> - interpreter.eval("X x/a+/").done (result) -> {operationsToPreview} = result - - runs -> - expect(operationsToPreview.length).toBeGreaterThan 3 - for operation in operationsToPreview - editSession = project.open(operation.getPath()) - editSession.setSelectedBufferRange(operation.execute(editSession)) - expect(editSession.getSelectedText()).toMatch /a+/ - editSession.destroy() - operation.destroy() - - editSession = null - - describe "nested commands", -> - describe "/regex/ /regex", -> - it "returns an error message if the last regex has no matches", -> - previousSelections = null - errorMessages = null - waitsForPromise -> - previousSelections = editSession.getSelectedBufferRanges() - interpreter.eval('/sort/ /no match', editSession).done (results) -> { errorMessages } = results - runs -> - expect(errorMessages.length).toBe 1 diff --git a/src/packages/command-panel/spec/command-panel-spec.coffee b/src/packages/command-panel/spec/command-panel-spec.coffee deleted file mode 100644 index 9485d8b78..000000000 --- a/src/packages/command-panel/spec/command-panel-spec.coffee +++ /dev/null @@ -1,597 +0,0 @@ -RootView = require 'root-view' -CommandPanelView = require 'command-panel/lib/command-panel-view' -shell = require 'shell' -_ = require 'underscore' - -describe "CommandPanel", -> - [editSession, buffer, commandPanel] = [] - - beforeEach -> - window.rootView = new RootView - rootView.open('sample.js') - rootView.enableKeymap() - editSession = rootView.getActivePaneItem() - buffer = editSession.buffer - commandPanelMain = atom.activatePackage('command-panel', immediate: true).mainModule - commandPanel = commandPanelMain.commandPanelView - commandPanel.history = [] - commandPanel.historyIndex = 0 - - describe "serialization", -> - it "preserves the command panel's history across reloads", -> - rootView.attachToDom() - rootView.trigger 'command-panel:toggle' - expect(commandPanel.miniEditor.isFocused).toBeTruthy() - commandPanel.execute('/.') - expect(commandPanel.history.length).toBe(1) - expect(commandPanel.history[0]).toBe('/.') - expect(commandPanel.historyIndex).toBe(1) - rootView.trigger 'command-panel:toggle' - expect(commandPanel.miniEditor.isFocused).toBeTruthy() - - atom.deactivatePackage('command-panel') - atom.activatePackage('command-panel') - - expect(rootView.find('.command-panel')).not.toExist() - rootView.trigger 'command-panel:toggle' - expect(rootView.find('.command-panel')).toExist() - commandPanel = rootView.find('.command-panel').view() - expect(commandPanel.history.length).toBe(1) - expect(commandPanel.history[0]).toBe('/.') - expect(commandPanel.historyIndex).toBe(1) - - it "only retains the configured max serialized history size", -> - rootView.attachToDom() - - commandPanel.maxSerializedHistorySize = 2 - commandPanel.execute('/test1') - commandPanel.execute('/test2') - commandPanel.execute('/test3') - expect(commandPanel.history.length).toBe(3) - expect(commandPanel.history[0]).toBe('/test1') - expect(commandPanel.history[1]).toBe('/test2') - expect(commandPanel.history[2]).toBe('/test3') - expect(commandPanel.historyIndex).toBe(3) - - atom.deactivatePackage('command-panel') - atom.activatePackage('command-panel') - - rootView.trigger 'command-panel:toggle' - commandPanel = rootView.find('.command-panel').view() - - expect(commandPanel.history.length).toBe(2) - expect(commandPanel.history[0]).toBe('/test2') - expect(commandPanel.history[1]).toBe('/test3') - expect(commandPanel.historyIndex).toBe(2) - - describe "when core:close is triggered on the command panel", -> - it "detaches the command panel, focuses the RootView and does not bubble the core:close event", -> - commandPanel.attach('command') - expect(commandPanel.miniEditor.getText()).toBe 'command' - rootViewCloseHandler = jasmine.createSpy('rootViewCloseHandler') - rootView.on 'core:close', rootViewCloseHandler - spyOn(rootView, 'focus') - - commandPanel.trigger('core:close') - - expect(rootView.focus).toHaveBeenCalled() - expect(rootViewCloseHandler).not.toHaveBeenCalled() - expect(commandPanel.hasParent()).toBeFalsy() - expect(commandPanel.miniEditor.getText()).toBe 'command' - - describe "when core:cancel is triggered on the command panel's mini editor", -> - it "detaches the command panel, focuses the RootView and does not bubble the core:cancel event", -> - commandPanel.attach('command') - expect(commandPanel.miniEditor.getText()).toBe 'command' - rootViewCancelHandler = jasmine.createSpy('rootViewCancelHandler') - rootView.on 'core:cancel', rootViewCancelHandler - spyOn(rootView, 'focus') - - commandPanel.miniEditor.trigger('core:cancel') - - expect(rootView.focus).toHaveBeenCalled() - expect(rootViewCancelHandler).not.toHaveBeenCalled() - expect(commandPanel.hasParent()).toBeFalsy() - expect(commandPanel.miniEditor.getText()).toBe 'command' - - describe "when command-panel:toggle is triggered on the root view", -> - beforeEach -> - rootView.attachToDom() - - describe "when the command panel is visible", -> - beforeEach -> - commandPanel.attach() - - describe "when the mini editor is focused", -> - it "closes the command panel", -> - expect(commandPanel.miniEditor.hiddenInput).toMatchSelector ':focus' - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeFalsy() - - describe "when the mini editor is not focused", -> - it "focuses the mini editor", -> - rootView.focus() - expect(commandPanel.miniEditor.hiddenInput).not.toMatchSelector ':focus' - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeTruthy() - expect(commandPanel.miniEditor.hiddenInput).toMatchSelector ':focus' - - describe "when the command panel is opened a second time", -> - it "displays and selects the previously entered text", -> - commandPanel.miniEditor.setText('command1') - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeFalsy() - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeTruthy() - expect(commandPanel.miniEditor.getText()).toBe 'command1' - expect(commandPanel.miniEditor.getSelectedText()).toBe 'command1' - - describe "when the command panel is not visible", -> - it "shows and focuses the command panel", -> - expect(commandPanel.hasParent()).toBeFalsy() - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeTruthy() - - describe "when command-panel:toggle-preview is triggered on the root view", -> - beforeEach -> - rootView.attachToDom() - - describe "when the preview list is/was previously visible", -> - beforeEach -> - rootView.trigger 'command-panel:toggle' - waitsForPromise -> commandPanel.execute('X x/quicksort/') - - describe "when the command panel is visible", -> - beforeEach -> - expect(commandPanel.hasParent()).toBeTruthy() - - describe "when the preview list is visible", -> - beforeEach -> - expect(commandPanel.previewList).toBeVisible() - - it "shows the expand and collapse all buttons", -> - expect(commandPanel.collapseAll).toBeVisible() - expect(commandPanel.expandAll).toBeVisible() - - describe "when the preview list is focused", -> - it "hides the command panel", -> - expect(commandPanel.previewList).toMatchSelector(':focus') - rootView.trigger 'command-panel:toggle-preview' - expect(commandPanel.hasParent()).toBeFalsy() - - describe "when the preview list is not focused", -> - it "focuses the preview list", -> - commandPanel.miniEditor.focus() - rootView.trigger 'command-panel:toggle-preview' - expect(commandPanel.previewList).toMatchSelector(':focus') - - describe "when the preview list is not visible", -> - beforeEach -> - commandPanel.miniEditor.focus() - rootView.trigger 'command-panel:toggle' - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeTruthy() - expect(commandPanel.previewList).toBeHidden() - - it "shows and focuses the preview list", -> - rootView.trigger 'command-panel:toggle-preview' - expect(commandPanel.previewList).toBeVisible() - expect(commandPanel.previewList).toMatchSelector(':focus') - - describe "when the command panel is not visible", -> - it "shows the command panel and the preview list, and focuses the preview list", -> - commandPanel.miniEditor.focus() - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeFalsy() - - rootView.trigger 'command-panel:toggle-preview' - expect(commandPanel.hasParent()).toBeTruthy() - expect(commandPanel.previewList).toBeVisible() - expect(commandPanel.previewList).toMatchSelector(':focus') - - describe "when the preview list has never been opened", -> - describe "when the command panel is visible", -> - beforeEach -> - rootView.trigger 'command-panel:toggle' - expect(commandPanel.hasParent()).toBeTruthy() - - describe "when the mini editor is focused", -> - it "retains focus on the mini editor and does not show the preview list or preview header", -> - expect(commandPanel.miniEditor.isFocused).toBeTruthy() - rootView.trigger 'command-panel:toggle-preview' - expect(commandPanel.previewList).toBeHidden() - expect(commandPanel.previewHeader).toBeHidden() - expect(commandPanel.miniEditor.isFocused).toBeTruthy() - - describe "when the mini editor is not focused", -> - it "focuses the mini editor and does not show the preview list or preview header", -> - rootView.focus() - rootView.trigger 'command-panel:toggle-preview' - expect(commandPanel.previewList).toBeHidden() - expect(commandPanel.previewHeader).toBeHidden() - expect(commandPanel.miniEditor.isFocused).toBeTruthy() - - describe "when the command panel is not visible", -> - it "shows the command panel and focuses the mini editor, but does not show the preview list", -> - - describe "when tool-panel:unfocus is triggered on the command panel", -> - it "returns focus to the root view but does not hide the command panel", -> - rootView.attachToDom() - commandPanel.attach() - expect(commandPanel.miniEditor.hiddenInput).toMatchSelector ':focus' - commandPanel.trigger 'tool-panel:unfocus' - expect(commandPanel.hasParent()).toBeTruthy() - expect(commandPanel.miniEditor.hiddenInput).not.toMatchSelector ':focus' - - describe "when command-panel:repeat-relative-address is triggered on the root view", -> - describe "when there is more than one match", -> - it "repeats the last search command if there is one", -> - rootView.trigger 'command-panel:repeat-relative-address' - - editSession.setCursorScreenPosition([4, 0]) - - commandPanel.execute("/current") - expect(editSession.getSelectedBufferRange()).toEqual [[5,6], [5,13]] - - rootView.trigger 'command-panel:repeat-relative-address' - expect(editSession.getSelectedBufferRange()).toEqual [[6,6], [6,13]] - - commandPanel.execute('s/r/R/g') - - rootView.trigger 'command-panel:repeat-relative-address' - expect(editSession.getSelectedBufferRange()).toEqual [[6,34], [6,41]] - - commandPanel.execute('0') - commandPanel.execute('/sort/ s/r/R/') # this contains a substitution... won't be repeated - - rootView.trigger 'command-panel:repeat-relative-address' - expect(editSession.getSelectedBufferRange()).toEqual [[3,31], [3,38]] - - describe "when there is only one match and it is selected", -> - it "maintains the current selection and plays a beep", -> - editSession.setCursorScreenPosition([0, 0]) - waitsForPromise -> - commandPanel.execute("/Array") - runs -> - expect(editSession.getSelectedBufferRange()).toEqual [[11,14], [11,19]] - spyOn(shell, 'beep') - rootView.trigger 'command-panel:repeat-relative-address' - waitsFor -> - shell.beep.callCount > 0 - runs -> - expect(editSession.getSelectedBufferRange()).toEqual [[11,14], [11,19]] - - describe "when command-panel:repeat-relative-address-in-reverse is triggered on the root view", -> - describe "when there is more than one match", -> - it "it repeats the last relative address in the reverse direction", -> - rootView.trigger 'command-panel:repeat-relative-address-in-reverse' - - editSession.setCursorScreenPosition([6, 0]) - - commandPanel.execute("/current") - expect(editSession.getSelectedBufferRange()).toEqual [[6,6], [6,13]] - - rootView.trigger 'command-panel:repeat-relative-address-in-reverse' - expect(editSession.getSelectedBufferRange()).toEqual [[5,6], [5,13]] - - describe "when there is only one match and it is selected", -> - it "maintains the current selection and plays a beep", -> - editSession.setCursorScreenPosition([0, 0]) - waitsForPromise -> - commandPanel.execute("/Array") - runs -> - expect(editSession.getSelectedBufferRange()).toEqual [[11,14], [11,19]] - spyOn(shell, 'beep') - rootView.trigger 'command-panel:repeat-relative-address-in-reverse' - waitsFor -> - shell.beep.callCount > 0 - runs -> - expect(editSession.getSelectedBufferRange()).toEqual [[11,14], [11,19]] - - describe "when command-panel:set-selection-as-regex-address is triggered on the root view", -> - it "sets the @lastRelativeAddress to a RegexAddress of the current selection", -> - rootView.open(require.resolve('fixtures/sample.js')) - rootView.getActivePaneItem().setSelectedBufferRange([[1,21],[1,28]]) - - commandInterpreter = commandPanel.commandInterpreter - expect(commandInterpreter.lastRelativeAddress).toBeUndefined() - rootView.trigger 'command-panel:set-selection-as-regex-address' - expect(commandInterpreter.lastRelativeAddress.subcommands.length).toBe 1 - expect(commandInterpreter.lastRelativeAddress.subcommands[0].regex.toString()).toEqual "/\\(items\\)/i" - - describe "when command-panel:find-in-file is triggered on an editor", -> - describe "when the command panel's editor does not begin with /", -> - it "pre-populates the command panel's editor with / and moves the cursor to the last column", -> - spyOn(commandPanel, 'attach').andCallThrough() - commandPanel.miniEditor.setText("foo") - commandPanel.miniEditor.setCursorBufferPosition([0, 0]) - - rootView.getActiveView().trigger "command-panel:find-in-file" - expect(commandPanel.attach).toHaveBeenCalled() - expect(commandPanel.parent).not.toBeEmpty() - expect(commandPanel.miniEditor.getText()).toBe "/" - expect(commandPanel.miniEditor.getCursorBufferPosition()).toEqual [0, 1] - - describe "when the command panel's editor begins with /", -> - it "selects text after the /", -> - spyOn(commandPanel, 'attach').andCallThrough() - commandPanel.miniEditor.setText("/foo") - commandPanel.miniEditor.setCursorBufferPosition([0, 0]) - - rootView.getActiveView().trigger "command-panel:find-in-file" - expect(commandPanel.attach).toHaveBeenCalled() - expect(commandPanel.parent).not.toBeEmpty() - expect(commandPanel.miniEditor.getText()).toBe "/foo" - expect(commandPanel.miniEditor.getSelectedText()).toBe "foo" - - describe "when command-panel:find-in-project is triggered on the root view", -> - describe "when the command panel's editor does not begin with Xx/", -> - it "pre-populates the command panel's editor with Xx/ and moves the cursor to the last column", -> - spyOn(commandPanel, 'attach').andCallThrough() - commandPanel.miniEditor.setText("foo") - commandPanel.miniEditor.setCursorBufferPosition([0, 0]) - - rootView.trigger "command-panel:find-in-project" - expect(commandPanel.attach).toHaveBeenCalled() - expect(commandPanel.parent).not.toBeEmpty() - expect(commandPanel.miniEditor.getText()).toBe "Xx/" - expect(commandPanel.miniEditor.getCursorBufferPosition()).toEqual [0, 3] - - describe "when the command panel's editor begins with Xx/", -> - it "selects text after the Xx/", -> - spyOn(commandPanel, 'attach').andCallThrough() - commandPanel.miniEditor.setText("Xx/foo") - commandPanel.miniEditor.setCursorBufferPosition([0, 0]) - - rootView.getActiveView().trigger "command-panel:find-in-project" - expect(commandPanel.attach).toHaveBeenCalled() - expect(commandPanel.parent).not.toBeEmpty() - expect(commandPanel.miniEditor.getText()).toBe "Xx/foo" - expect(commandPanel.miniEditor.getSelectedText()).toBe "foo" - - describe "when return is pressed on the panel's editor", -> - describe "if the command has an immediate effect", -> - it "executes it immediately on the current buffer", -> - rootView.trigger 'command-panel:toggle' - commandPanel.miniEditor.insertText ',s/sort/torta/g' - commandPanel.miniEditor.hiddenInput.trigger keydownEvent('enter') - - expect(buffer.lineForRow(0)).toMatch /quicktorta/ - expect(buffer.lineForRow(1)).toMatch /var torta/ - - describe "when the command returns operations to be previewed", -> - beforeEach -> - rootView.getActivePane().remove() - rootView.attachToDom() - rootView.trigger 'command-panel:toggle' - waitsForPromise -> commandPanel.execute('X x/quicksort/') - - it "displays and focuses the operation preview list", -> - expect(commandPanel).toBeVisible() - expect(commandPanel.previewList).toBeVisible() - expect(commandPanel.previewList).toMatchSelector ':focus' - previewItem = commandPanel.previewList.find("li:contains(sample.js):first") - expect(previewItem.find('.path-details').text()).toBe "sample.js(1)" - expect(previewItem.next().find('.preview').text()).toBe "var quicksort = function () {" - expect(previewItem.next().find('.preview > .match').text()).toBe "quicksort" - - rootView.trigger 'command-panel:toggle-preview' # ensure we can close panel without problems - expect(commandPanel).toBeHidden() - - it "destroys previously previewed operations if there are any", -> - waitsForPromise -> commandPanel.execute('X x/pivot/') - # there shouldn't be any dangling operations after this - - describe "if the command is malformed", -> - it "adds and removes an error class to the command panel and does not close it or display a loading message", -> - rootView.attachToDom() - rootView.trigger 'command-panel:toggle' - commandPanel.miniEditor.insertText 'garbage-command!!' - - commandPanel.miniEditor.hiddenInput.trigger keydownEvent('enter') - expect(commandPanel.parent()).toExist() - expect(commandPanel).toHaveClass 'error' - expect(commandPanel.loadingMessage).toBeHidden() - - advanceClock 400 - - expect(commandPanel).not.toHaveClass 'error' - - describe "if the command returns an error message", -> - beforeEach -> - rootView.attachToDom() - rootView.trigger 'command-panel:toggle' - commandPanel.miniEditor.insertText '/garbage' - expect(commandPanel.errorMessages).not.toBeVisible() - commandPanel.miniEditor.hiddenInput.trigger keydownEvent('enter') - - it "adds and removes an error class to the command panel and displays the error message", -> - expect(commandPanel).toBeVisible() - expect(commandPanel.errorMessages).toBeVisible() - expect(commandPanel).toHaveClass 'error' - - it "removes the error message when the command-panel is toggled", -> - rootView.trigger 'command-panel:toggle' # off - rootView.trigger 'command-panel:toggle' # on - expect(commandPanel).toBeVisible() - expect(commandPanel.errorMessages).not.toBeVisible() - - describe "when the command contains an escaped character", -> - it "executes the command with the escaped character (instead of as a backslash followed by the character)", -> - rootView.trigger 'command-panel:toggle' - - editSession = rootView.open(require.resolve 'fixtures/sample-with-tabs.coffee') - commandPanel.miniEditor.setText "/\\tsell" - commandPanel.miniEditor.hiddenInput.trigger keydownEvent('enter') - expect(editSession.getSelectedBufferRange()).toEqual [[3,1],[3,6]] - - describe "when move-up and move-down are triggerred on the editor", -> - it "navigates forward and backward through the command history", -> - commandPanel.execute 's/war/peace/g' - commandPanel.execute 's/twinkies/wheatgrass/g' - - rootView.trigger 'command-panel:toggle' - - commandPanel.miniEditor.trigger 'core:move-up' - expect(commandPanel.miniEditor.getText()).toBe 's/twinkies/wheatgrass/g' - commandPanel.miniEditor.trigger 'core:move-up' - expect(commandPanel.miniEditor.getText()).toBe 's/war/peace/g' - commandPanel.miniEditor.trigger 'core:move-up' - expect(commandPanel.miniEditor.getText()).toBe 's/war/peace/g' - commandPanel.miniEditor.trigger 'core:move-down' - expect(commandPanel.miniEditor.getText()).toBe 's/twinkies/wheatgrass/g' - commandPanel.miniEditor.trigger 'core:move-down' - expect(commandPanel.miniEditor.getText()).toBe '' - - describe "when the preview list is focused with search operations", -> - previewList = null - - beforeEach -> - previewList = commandPanel.previewList - rootView.trigger 'command-panel:toggle' - waitsForPromise -> commandPanel.execute('X x/sort/') - - it "displays the number of files and operations", -> - rootView.attachToDom() - expect(commandPanel.previewCount.text()).toBe '22 matches in 5 files' - - describe "when move-down and move-up are triggered on the preview list", -> - it "selects the next/previous operation (if there is one), and scrolls the list if needed", -> - rootView.attachToDom() - expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0] - - previewList.trigger 'core:move-down' - expect(previewList.find('li.operation:eq(1)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[1] - - previewList.trigger 'core:move-down' - expect(previewList.find('li.operation:eq(2)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[2] - - previewList.trigger 'core:move-up' - expect(previewList.find('li.operation:eq(1)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[1] - - _.times previewList.getOperations().length + previewList.getPathCount(), -> previewList.trigger 'core:move-down' - - expect(previewList.find("li.operation:last")).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe _.last(previewList.getOperations()) - - expect(previewList.scrollBottom()).toBeCloseTo previewList.prop('scrollHeight'), -1 - - _.times previewList.getOperations().length + previewList.getPathCount(), -> previewList.trigger 'core:move-up' - expect(previewList.scrollTop()).toBe 0 - - it "doesn't bubble up the event and the command panel text doesn't change", -> - rootView.attachToDom() - commandPanel.miniEditor.setText "command" - previewList.focus() - previewList.trigger 'core:move-down' - expect(previewList.find('li.operation:eq(1)')).toHaveClass 'selected' - expect(commandPanel.miniEditor.getText()).toBe 'command' - previewList.trigger 'core:move-up' - expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected' - expect(commandPanel.miniEditor.getText()).toBe 'command' - - it "doesn't select collapsed operations", -> - rootView.attachToDom() - previewList.trigger 'command-panel:collapse-result' - expect(previewList.find('li.path:eq(0)')).toHaveClass 'selected' - previewList.trigger 'core:move-down' - expect(previewList.find('li.path:eq(1)')).toHaveClass 'selected' - previewList.trigger 'core:move-up' - expect(previewList.find('li.path:eq(0)')).toHaveClass 'selected' - - describe "when move-to-top and move-to-bottom are triggered on the preview list", -> - it "selects the first path or last operation", -> - rootView.attachToDom() - expect(previewList.getOperations().length).toBeGreaterThan 0 - expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0] - - previewList.trigger 'core:move-to-bottom' - expect(previewList.find('li.operation:last')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBe _.last(previewList.getOperations()) - - previewList.trigger 'core:move-to-top' - expect(previewList.find('li.path:eq(0)')).toHaveClass 'selected' - expect(previewList.getSelectedOperation()).toBeUndefined() - - describe "when core:confirm is triggered on the preview list", -> - it "opens the operation's buffer, selects and scrolls to the search result, and refocuses the preview list", -> - rootView.height(200) - rootView.attachToDom() - - waitsForPromise -> commandPanel.execute('X x/apply/') # use apply because it is at the end of the file - runs -> - spyOn(previewList, 'focus') - executeHandler = jasmine.createSpy('executeHandler') - commandPanel.on 'core:confirm', executeHandler - - _.times 4, -> previewList.trigger 'core:move-down' - operation = previewList.getSelectedOperation() - - previewList.trigger 'core:confirm' - - editSession = rootView.getActivePaneItem() - expect(editSession.buffer.getPath()).toBe project.resolve(operation.getPath()) - expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange() - expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange() - expect(rootView.getActiveView().isScreenRowVisible(editSession.getCursorScreenRow())).toBeTruthy() - expect(previewList.focus).toHaveBeenCalled() - - expect(executeHandler).not.toHaveBeenCalled() - - it "toggles the expansion state when a path is selected", -> - rootView.attachToDom() - previewList.trigger 'core:move-to-top' - expect(previewList.find('li.path:first')).toHaveClass 'selected' - expect(previewList.find('li.path:first')).not.toHaveClass 'is-collapsed' - previewList.trigger 'core:confirm' - expect(previewList.find('li.path:first')).toHaveClass 'selected' - expect(previewList.find('li.path:first')).toHaveClass 'is-collapsed' - - describe "when an operation in the preview list is clicked", -> - it "opens the operation's buffer, selects the search result, and refocuses the preview list", -> - spyOn(previewList, 'focus') - operation = previewList.getOperations()[4] - - previewList.find('li.operation:eq(4) span').mousedown() - - expect(previewList.getSelectedOperation()).toBe operation - editSession = rootView.getActivePaneItem() - expect(editSession.buffer.getPath()).toBe project.resolve(operation.getPath()) - expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange() - expect(previewList.focus).toHaveBeenCalled() - - describe "when a path in the preview list is clicked", -> - it "shows and hides the matches for that path", -> - rootView.attachToDom() - expect(previewList.find('li.path:first-child ul.matches')).toBeVisible() - previewList.find('li.path:first-child .path-details').mousedown() - expect(previewList.find('li.path:first-child ul.matches')).toBeHidden() - - previewList.find('li.path:first-child .path-details').mousedown() - expect(previewList.find('li.path:first-child ul.matches')).toBeVisible() - - describe "when command-panel:collapse-result and command-panel:expand-result are triggered", -> - it "collapses and selects the path, and then expands the selected path", -> - rootView.attachToDom() - expect(previewList.find('li.path:first-child ul.matches')).toBeVisible() - previewList.trigger 'command-panel:collapse-result' - expect(previewList.find('li.path:first-child ul.matches')).toBeHidden() - expect(previewList.find('li.path:first-child')).toHaveClass 'selected' - previewList.trigger 'command-panel:expand-result' - expect(previewList.find('li.path:first-child ul.matches')).toBeVisible() - expect(previewList.find('li.path:first-child')).toHaveClass 'selected' - - describe "when the active pane item is not an EditSession", -> - it "doesn't throw an error (regression)", -> - rootView.open('binary-file.png') - rootView.trigger 'command-panel:toggle' - - executePromise = null - expect(-> executePromise = commandPanel.execute('Xx/sort/')).not.toThrow() - - waitsForPromise -> executePromise diff --git a/src/packages/command-panel/spec/preview-list-spec.coffee b/src/packages/command-panel/spec/preview-list-spec.coffee deleted file mode 100644 index f1bfafa85..000000000 --- a/src/packages/command-panel/spec/preview-list-spec.coffee +++ /dev/null @@ -1,67 +0,0 @@ -RootView = require 'root-view' -CommandPanelView = require 'command-panel/lib/command-panel-view' -_ = require 'underscore' - -describe "Preview List", -> - [previewList, commandPanelMain, commandPanelView] = [] - - beforeEach -> - window.rootView = new RootView() - rootView.attachToDom() - commandPanelMain = atom.activatePackage('command-panel', immediate: true).mainModule - commandPanelView = commandPanelMain.commandPanelView - previewList = commandPanelView.previewList - rootView.trigger 'command-panel:toggle' - - describe "when the list is scrollable", -> - it "adds more operations to the DOM when `scrollBottom` nears the `pixelOverdraw`", -> - waitsForPromise -> - commandPanelView.execute('X x/so/') - - runs -> - expect(previewList.prop('scrollHeight')).toBeGreaterThan previewList.height() - previousScrollHeight = previewList.prop('scrollHeight') - previousOperationCount = previewList.find("li").length - - previewList.scrollTop(previewList.pixelOverdraw / 2) - previewList.trigger('scroll') # Not sure why scroll event isn't being triggered on it's own - expect(previewList.prop('scrollHeight')).toBe previousScrollHeight - expect(previewList.find("li").length).toBe previousOperationCount - - previewList.scrollToBottom() - previewList.trigger('scroll') # Not sure why scroll event isn't being triggered on it's own - expect(previewList.prop('scrollHeight')).toBeGreaterThan previousScrollHeight - expect(previewList.find("li").length).toBeGreaterThan previousOperationCount - - it "renders all operations if the preview items are collapsed", -> - waitsForPromise -> - commandPanelView.execute('X x/so/') - - runs -> - expect(previewList.prop('scrollHeight')).toBeGreaterThan previewList.height() - previousScrollHeight = previewList.prop('scrollHeight') - previousOperationCount = previewList.find("li").length - previewList.collapseAllPaths() - expect(previewList.find("li").length).toBeGreaterThan previousOperationCount - - it "renders more operations when a preview item is collapsed", -> - waitsForPromise -> - commandPanelView.execute('X x/so/') - - runs -> - expect(previewList.prop('scrollHeight')).toBeGreaterThan previewList.height() - previousScrollHeight = previewList.prop('scrollHeight') - previousOperationCount = previewList.find("li").length - previewList.trigger 'command-panel:collapse-result' - expect(previewList.find("li").length).toBeGreaterThan previousOperationCount - - it "renders all operations when core:move-to-bottom is triggered", -> - waitsForPromise -> - commandPanelView.execute('X x/so/') - - runs -> - expect(previewList.prop('scrollHeight')).toBeGreaterThan previewList.height() - previousScrollHeight = previewList.prop('scrollHeight') - previewList.trigger 'core:move-to-bottom' - liCount = previewList.getPathCount() + previewList.getOperations().length - expect(previewList.find("li").length).toBe liCount diff --git a/src/packages/command-panel/stylesheets/command-panel.less b/src/packages/command-panel/stylesheets/command-panel.less deleted file mode 100644 index 0d25fc13c..000000000 --- a/src/packages/command-panel/stylesheets/command-panel.less +++ /dev/null @@ -1,151 +0,0 @@ -@import "octicon-utf-codes.less"; -@import "octicon-mixins.less"; - -.command-panel { - position: relative; - padding: 0; - - .is-loading { - margin-bottom: 10px; - text-align: center; - - span { - padding: 5px 10px 5px 10px; - background-color: #111111; - text-align: center; - border-radius: 3px; - border: 1px solid rgba(255,255,255,0.1); - border-top: 1px solid rgba(0,0,0,1); - border-left: 1px solid rgba(0,0,0,1); - - .octicon(hourglass, 1.1em); - - &:before { - margin-right: 5px; - } - } - } - - .preview-count { - display: inline-block; - margin-top: 4px; - font-size: 11px; - -webkit-user-select: none; - } - - .preview-list { - max-height: 300px; - overflow: auto; - margin: 0 0 10px 0; - position: relative; - cursor: default; - - .path { - position: relative; - -webkit-user-select: none; - } - - .path-details { - .octicon(chevron-down, 12px); - - &:before { - margin-right: 5px; - margin-left: 5px; - position: relative; - top: 0; - } - } - - .is-collapsed .path-details:before { - content: @chevron-right; - } - - .path-name { - .octicon(file-text); - - &:before { - margin-right: 5px; - position: relative; - top: 1px; - } - } - - .path.readme .path-name:before { - content: @book; - } - - .operation { - padding-top: 2px; - padding-bottom: 2px; - padding-left: 10px; - } - - .line-number { - margin-right: 1ex; - text-align: right; - display: inline-block; - } - - .path-match-number { - padding-left: 8px; - } - - .preview { - word-break: break-all; - - .match { - -webkit-border-radius: 2px; - padding: 1px; - } - } - - .matches { - list-style-type: none; - margin: 0; - } - } - - .header:after { - content: "."; - display: block; - visibility: hidden; - clear: both; - height: 0; - } - - .expand-collapse { - float: right; - -webkit-user-select: none; - margin: 0; - - li { - display: inline-block; - cursor: pointer; - font-size: 11px; - margin-left: 5px; - padding: 5px 10px; - border-radius: 3px; - line-height: normal; - } - } - - .prompt-and-editor { - display: -webkit-flex; - - .editor { - position: relative; - -webkit-flex: 1; - } - } - - .error-messages { - list-style-type: none; - margin: 0; - padding: 5px 1em; - color: white; - } - - .btn { - margin-left: 5px; - } -}