Use LikeView in comments

Use LikeView in comments

--- client/app/CommonViews/comments/commentlistitemview.coffee
+++ client/app/CommonViews/comments/commentlistitemview.coffee
@@ -12,36 +12,22 @@
     originType  = data.getAt('originType')
     deleterId   = data.getAt('deletedBy')?.getId?()

-    origin = {
+    origin =
       constructorName  : originType
       id               : originId
-    }
+
     @avatar = new AvatarView {
-      size    : {width: 30, height: 30}
-      origin
-    }
-    @author = new ProfileLinkView {
+      size     :
+        width  : 30
+        height : 30
       origin
     }

+    @author = new ProfileLinkView { origin }
+
     if deleterId? and deleterId isnt originId
       @deleter = new ProfileLinkView {}, data.getAt('deletedBy')
-    # if data.originId is KD.whoami().getId()
-    #   @settingsButton = new KDButtonViewWithMenu
-    #     style       : 'transparent activity-settings-context'
-    #     cssClass    : 'activity-settings-menu'
-    #     title       : ''
-    #     icon        : yes
-    #     delegate    : @
-    #     iconClass   : "cog"
-    #     menu        : [
-    #       type      : "contextmenu"
-    #       items     : [
-    #         { title : 'Delete', id : 2,  parentId : null, callback : => data.delete (err)=> @propagateEvent KDEventType: 'CommentIsDeleted' }
-    #       ]
-    #     ]
-    #     callback    : (event)=> @settingsButton.contextMenu event
-    # else
+
     @deleteLink = new KDCustomHTMLView
       tagName     : 'a'
       attributes  :
@@ -60,86 +46,27 @@
           listenedToInstance : @deleteLink
           callback           : => @confirmDeleteComment data

-    @likeCount    = new ActivityLikeCount
-      tooltip     :
-        gravity   : "se"
-        title     : ""
-        engine    : "tipsy" # We should force to use tipsy because
-                            # for now only tipsy supports tooltip updates
-      attributes  :
-        href      : "#"
-        title     : "Click to view..."
-      click       : =>
-        if data.meta.likes > 0 # 3
-          data.fetchLikedByes {},
-            sort  : timestamp : -1
-            , (err, likes) =>
-              new FollowedModalView {title:"Members who liked #{data.body}"}, likes
-      , data
-
-    @likeCount.on "countChanged", (count) =>
-      @updateLikeState yes
-
-    @likeLink     = new ActivityActionLink
-
-  updateLikeState:(checkIfILiked = no)->
-
-    data = @getData()
-
-    if data.meta.likes is 0
-      @likeLink.updatePartial "Like"
-      return
-
-    data.fetchLikedByes {},
-      limit : if checkIfILiked then data.meta.likes else 3
-      sort  : timestamp : -1
-
-      , (err, likes) =>
-
-        peopleWhoLiked   = []
-
-        if likes
-          if checkIfILiked
-            {_id}       = KD.whoami()
-            likedBefore = likes.filter((item)-> item._id is _id).length > 0
-
-          likes.forEach (item)=>
-            if peopleWhoLiked.length < 3
-              {firstName, lastName} = item.profile
-              peopleWhoLiked.push "" + firstName + " " + lastName + ""
-            else return
-
-          if data.meta.likes is 1
-            tooltip = peopleWhoLiked[0]
-          else if data.meta.likes is 2
-            tooltip = peopleWhoLiked[0] + " and " + peopleWhoLiked[1]
-          else if data.meta.likes is 3
-            tooltip = peopleWhoLiked[0] + ", " + peopleWhoLiked[1] + " and " + peopleWhoLiked[2]
-          else
-            tooltip = peopleWhoLiked[0] + ", " + peopleWhoLiked[1] + " and " + (data.meta.likes - 2) + " more."
-
-          @likeCount.updateTooltip {title: tooltip }
-
-          if checkIfILiked
-            @likeLink.updatePartial if likedBefore then "Unlike" else "Like"
+    @likeView = new LikeView {}, data

   render:->
     if @getData().getAt 'deletedAt'
       @emit 'CommentIsDeleted'
-    @setTemplate @pistachio()
+    @updateTemplate()
     super

   viewAppended:->
-    @setTemplate @pistachio()
+    @updateTemplate yes
     @template.update()
-    # super unless @_partialUpdated

   click:(event)->
-    $trg = $(event.target)
-    more = "span.collapsedtext a.more-link"
-    less = "span.collapsedtext a.less-link"
-    $trg.parent().addClass("show").removeClass("hide") if $trg.is(more)
-    $trg.parent().removeClass("show").addClass("hide") if $trg.is(less)
+
+    if $(event.target).is("span.collapsedtext a.more-link")
+      @$("span.collapsedtext").addClass "show"
+      @$("span.collapsedtext").removeClass "hide"
+
+    if $(event.target).is("span.collapsedtext a.less-link")
+      @$("span.collapsedtext").removeClass "show"
+      @$("span.collapsedtext").addClass "hide"

     if $(event.target).is "span.avatar a, a.user-fullname"
       {originType, originId} = @getData()
@@ -148,9 +75,10 @@
           appManager.tell "Members", "createContentDisplay", origin

   confirmDeleteComment:(data)->
+    {type} = @getOptions()
     modal = new KDModalView
-      title          : "Delete comment"
-      content        : "
Are you sure you want to delete this comment?
"
+      title          : "Delete #{type}"
+      content        : "
Are you sure you want to delete this #{type}?
"
       height         : "auto"
       overlay        : yes
       buttons        :
@@ -169,28 +97,30 @@
                 type     : "mini"
                 cssClass : "error editor"
                 title     : "Error, please try again later!"
-        # cancel       :
-        #   style      : "modal-cancel"
-        #   callback   : => modal.destroy()
+
+  updateTemplate:(force = no)->
+    if @getData().getAt 'deletedAt'
+      {type} = @getOptions()
+      @setClass "deleted"
+      if @deleter
+        @setTemplate "
{{> @author}}'s #{type} has been deleted by {{> @deleter}}.
"
+      else
+       @setTemplate "
{{> @author}}'s #{type} has been deleted.
"
+    else if force
+      @setTemplate @pistachio()

   pistachio:->
-    if @getData().getAt 'deletedAt'
-      @setClass "deleted"
-      if @deleter
-        "
{{> @author}}'s comment has been deleted by {{> @deleter}}.
"
-      else
-        "
{{> @author}}'s comment has been deleted.
"
-    else
-      """
-

-        {{> @avatar}}
-

-          {{> @deleteLink}}
-

-            {{> @author}}
-            {{@utils.applyTextExpansions #(body), yes}}
-

-          <time>{{$.timeago #(meta.createdAt)}}</time>
-

+    """
+

+      {{> @avatar}}
+

+

+          {{> @author}}
+          {{@utils.applyTextExpansions #(body), yes}}
+

+        {{> @deleteLink}}
+        {{> @likeView}}
+        <time>{{$.timeago #(meta.createdAt)}}</time>

-      """
+

+    """


:lipstick:

:lipstick:

--- src/packages/tree-view/src/directory-view.coffee
+++ src/packages/tree-view/src/directory-view.coffee
@@ -23,17 +23,15 @@
     @disclosureArrow.on 'click', => @toggleExpansion()

     repo = @project.repo
+    iconClass = 'directory-icon'
     if repo?
       path = @directory.getPath()
-      @directoryName.addClass('ignored') if parent and repo.isPathIgnored(path)
-      if not parent and path is repo.getWorkingDirectory()
-        @directoryName.addClass('repository-icon')
-      else if repo.isSubmodule(path)
-        @directoryName.addClass('submodule-icon')
+      if parent
+        @directoryName.addClass('ignored') if repo.isPathIgnored(path)
+        iconClass = 'submodule-icon' if repo.isSubmodule(path)
       else
-        @directoryName.addClass('directory-icon')
-    else
-      @directoryName.addClass('directory-icon')
+        iconClass = 'repository-icon' if path is repo.getWorkingDirectory()
+    @directoryName.addClass(iconClass)

   getPath: ->
     @directory.path


Only look for JSON keymaps

Only look for JSON keymaps

--- build/tasks/compile-packages-slug-task.coffee
+++ build/tasks/compile-packages-slug-task.coffee
@@ -18,7 +18,7 @@
   getKeymaps = (appDir) ->
     keymapsPath = path.join(appDir, 'keymaps')
     keymaps = {}
-    for keymapPath in fs.listSync(keymapsPath, ['.cson', '.json'])
+    for keymapPath in fs.listSync(keymapsPath, ['.json'])
       name = path.basename(keymapPath, path.extname(keymapPath))
       continue unless OtherPlatforms.indexOf(name) is -1


tabs dont handle cmd-w

tabs dont handle cmd-w

--- extensions/tabs/key-bindings.coffee
+++ extensions/tabs/key-bindings.coffee
@@ -1,5 +1,4 @@
 tabs:
-  'cmd-w': (tabs) -> tabs.pane.closeActiveTab()
   'cmd-shift-{': (tabs) -> tabs.pane.prevTab()
   'cmd-shift-}': (tabs) -> tabs.pane.nextTab()
   'cmd-1': (tabs) -> tabs.pane.switchToTab 1


mustache fix erything. closes #43

mustache fix erything. closes #43

--- extensions/tabs/key-bindings.coffee
+++ extensions/tabs/key-bindings.coffee
@@ -1,7 +1,7 @@
 tabs:
   'cmd-w': (tabs) -> tabs.pane.closeActiveTab()
-  'cmd-shift-[': (tabs) -> tabs.pane.prevTab()
-  'cmd-shift-]': (tabs) -> tabs.pane.nextTab()
+  'cmd-shift-{': (tabs) -> tabs.pane.prevTab()
+  'cmd-shift-}': (tabs) -> tabs.pane.nextTab()
   'cmd-1': (tabs) -> tabs.pane.switchToTab 1
   'cmd-2': (tabs) -> tabs.pane.switchToTab 2
   'cmd-3': (tabs) -> tabs.pane.switchToTab 3


How did a semicolon make it in there?

How did a semicolon make it in there?

--- src/kona.coffee
+++ src/kona.coffee
@@ -3,7 +3,7 @@
 # Debug helpers
 # Set this to true to log info to the console
 # Make sure to disable for production dists
-Kona.debugMode = true;
+Kona.debugMode = true

 Kona.debug = (msg) ->
   console.log msg if Kona.debugMode


Correct status check

Correct status check

--- src/components/WebService/Basecamp/BasecampComponent.coffee
+++ src/components/WebService/Basecamp/BasecampComponent.coffee
@@ -40,7 +40,7 @@
             resp.setEncoding "utf8"
             body = ""
             resp.on "data", (data) ->
-                throw resp.headers.status unless resp.statusCode > 400
+                throw resp.headers.status unless resp.statusCode < 400
                 body += data
             resp.on "end", ->
                 success body


use OutputCacheManager to construct static path to files

--- services/clsi/app.coffee
+++ services/clsi/app.coffee
@@ -12,6 +12,7 @@
 Metrics.open_sockets.monitor(logger)

 ProjectPersistenceManager = require "./app/js/ProjectPersistenceManager"
+OutputCacheManager = require "./app/js/OutputCacheManager"

 require("./app/js/db").sync()

@@ -68,8 +69,8 @@
 		res.set("Content-Type", "text/plain")

 app.get "/project/:project_id/output/*", require("./app/js/SymlinkCheckerMiddlewear"), (req, res, next) ->
-	if req.query?.build? && req.query.build.match(/^[0-9]+$/)
-		req.url = "/#{req.params.project_id}/.cache/clsi/#{req.query.build}/#{req.params[0]}"
+	if req.query?.build? && req.query.build.match(OutputCacheManager.BUILD_REGEX)
+		req.url = "/#{req.params.project_id}/" + OutputCacheManager.path(req.query.build) + "/#{req.params[0]}"
 	else
 		req.url = "/#{req.params.project_id}/#{req.params[0]}"
 	staticServer(req, res, next)


daily

daily


Reduced number of attempts warning for finding canonical signature #169

--- dl/src/ecc/signature.coffee
+++ dl/src/ecc/signature.coffee
@@ -67,7 +67,7 @@
                 break

             # signing is slow, keep an eye out for this...
-            if nonce % 1 == 0
+            if nonce % 10 == 0
                 console.log "WARN: #{nonce} attempts to find canonical signature"

         new Signature ecsignature.r, ecsignature.s, i


Fix frame not showing.

Fix frame not showing.

--- src/main.coffee
+++ src/main.coffee
@@ -133,8 +133,7 @@

     icon_name = if process.platform is 'win32' then 'icon@2.png' else 'icon@32.png'

-    # Create the browser window.
-    mainWindow = new BrowserWindow {
+    windowOpts = {
         width: 730
         height: 590
         "min-width": 620
@@ -146,10 +145,15 @@
             nodeIntegration: true
             # preload: path.join(app.getAppPath(), 'ui', 'app.js')
         }
-        titleBarStyle: 'hiddenInset' if process.platform is 'darwin'
-        frame: false if process.platform is 'win32'
         # autoHideMenuBar : true unless process.platform is 'darwin'
     }
+
+    if process.platform is 'darwin'
+        windowOpts.titleBarStile = 'hiddenInset'
+        windowOpts.frame = false
+
+    # Create the browser window.
+    mainWindow = new BrowserWindow windowOpts

     # Launch fullscreen with DevTools open, usage: npm run debug
     if debug


Flex handle: Added flex-open event. See #55262

--- src/base/FlexHandle/FlexHandle.coffee
+++ src/base/FlexHandle/FlexHandle.coffee
@@ -432,9 +432,12 @@
 		@

 	open: ->
-	# console.debug "FlexHandle.show", @__uniqueId, @isOpen()
 		if @isOpen()
 			return @
+
+		CUI.Events.trigger
+			node: @getPane()
+			type: "flex-open"

 		@_element.classList.remove("cui-flex-handle-closed")
 		CUI.dom.setStyleOne(@__pane, "display", "")
@@ -450,7 +453,6 @@
 		@

 	show: ->
-	# console.debug "FlexHandle.show", @__uniqueId, @isShown()
 		if @isShown()
 			return @
 		@_element.classList.remove("cui-flex-handle-hidden")
@@ -510,5 +512,5 @@

 CUI.Events.registerEvent
-	type: ["flex-stretch-start", "flex-stretch-end", "flex-close"]
+	type: ["flex-stretch-start", "flex-stretch-end", "flex-close", "flex-open"]
 	sink: true


UI/core making the Modal unit to set up Modal.current reference automatically

--- ui/core/src/modal.coffee
+++ ui/core/src/modal.coffee
@@ -4,6 +4,9 @@
 # Copyright (C) 2012 Nikolay Nemshilov
 #
 class Modal extends Element
+  extend:
+    current: null
+
   #
   # Basic constructor
   #
@@ -87,10 +90,13 @@
     @insertTo(document.body)
     @$super.apply(@, arguments)

+    Modal.current = @costructor.current = @
+
   #
   # Removes the whole thing out of the `document.body`
   #
   hide: ()->
+    Modal.current = @costructor.current = null
     @remove()


fix path rendering to handle wrapped sub paths

--- src/path.coffee
+++ src/path.coffee
@@ -84,18 +84,23 @@
       curve = curve.concat(toNode.point.toArray())
       'C' + curve.join(',')

+    closePath = (firstNode, lastNode)->
+      closingPath = ''
+      closingPath += makeCurve(lastNode, firstNode) if lastNode.handleOut or firstNode.handleIn
+      closingPath += 'Z'
+
     for node in @nodes
       if node.isMoveNode or !path
+        firstNode = node
         path += 'M' + node.point.toArray().join(',')
       else
         path += makeCurve(lastNode, node)
-      path += 'Z' if node.isCloseNode
+
       lastNode = node
+      path += closePath(firstNode, lastNode) if node.isCloseNode

     if @isClosed and path[path.length - 1] != 'Z'
-      [firstNode, lastNode] = [@nodes[0], @nodes[@nodes.length-1]]
-      path += makeCurve(lastNode, firstNode) if lastNode.handleOut or firstNode.handleIn
-      path += 'Z'
+      closePath(firstNode, @nodes[@nodes.length-1])

     path


webpack: avoid creating chunks, such that there is no problem with them being missing after a webapp update

--- src/webpack.config.coffee
+++ src/webpack.config.coffee
@@ -369,7 +369,8 @@
     # plugins.push new webpack.optimize.CommonsChunkPlugin(name: "lib")
     plugins.push new webpack.optimize.DedupePlugin()
     plugins.push new webpack.optimize.OccurenceOrderPlugin()
-    plugins.push new webpack.optimize.LimitChunkCountPlugin(maxChunks: 10)
+    # TODO change this back to a number at about 10, once we know how to keep old chunks around
+    plugins.push new webpack.optimize.LimitChunkCountPlugin(maxChunks: 1)
     plugins.push new webpack.optimize.MinChunkSizePlugin(minChunkSize: 32768)
     # to get source maps working in production mode, one has to figure out how
     # to get inSourceMap/outSourceMap working here.


Add window:log-deprecation-warnings command

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -3,7 +3,7 @@
 Q = require 'q'
 _ = require 'underscore-plus'
 Delegator = require 'delegato'
-{deprecate} = require 'grim'
+{deprecate, logDeprecationWarnings} = require 'grim'
 scrollbarStyle = require 'scrollbar-style'
 {$, $$, View} = require './space-pen-extensions'
 fs = require 'fs-plus'
@@ -141,8 +141,8 @@
     @command 'window:focus-pane-on-left', => @focusPaneViewOnLeft()
     @command 'window:focus-pane-on-right', => @focusPaneViewOnRight()
     @command 'window:save-all', => @saveAll()
-    @command 'window:toggle-invisibles', =>
-      atom.config.toggle("editor.showInvisibles")
+    @command 'window:toggle-invisibles', => atom.config.toggle("editor.showInvisibles")
+    @command 'window:log-deprecation-warnings', => logDeprecationWarnings()

     @command 'window:toggle-auto-indent', =>
       atom.config.toggle("editor.autoIndent")


Add `opacity-transitionable`.

Add `opacity-transitionable`.

This will also add support for transitions with Zepto.js.

--- src/chaplin/views/collection_view.coffee
+++ src/chaplin/views/collection_view.coffee
@@ -310,6 +310,7 @@

       if included
         # Make view transparent if animation is enabled
+        $viewEl.addClass 'opacity-transitionable' if animationDuration
         $viewEl.css 'opacity', 0 if animationDuration
       else
         # Hide the view if it’s filtered
@@ -342,6 +343,7 @@

       # Fade the view in if it was made transparent before
       if animationDuration and included
+        $viewEl.addClass 'opacity-transitionable-end'
         $viewEl.animate {opacity: 1}, animationDuration

     # Remove the view for an item


try-catch

try-catch

--- src/poll.coffee
+++ src/poll.coffee
@@ -44,36 +44,42 @@
 	# 			#{optionsString}
 	# 			"""
 	robot.respond /start poll (.*?)\s(option:\s?.*)+/i, (msg) ->
-		@robot.logger.info "Create poll called: #{msg}"
-		topic = msg.match[1]
-		@robot.logger.info "Topic: #{topic}"
-		options = msg.match[2]
-		@robot.logger.info "options: #{options}"
-		# @robot.logger.info createPoll
-		# response = createPoll topic, options
-		@robot.logger.info "Creating poll with #{topic}"
-		id = ""
-		possibleValues = "0123456789abcdef"
-		id += possibleValues.charAt(Math.floor(Math.random() * possibleValues.length)) for [1..5]
-		pollOptions = (options.split "option: ")[1..]
-		@robot.logger.info "We have #{pollOptions.length()} options"
-		@robot.brain.data.poll[id].topic = topic
-		optionsString = ""
+		try
+			@robot.logger.info "Create poll called: #{msg}"
+			topic = msg.match[1]
+			@robot.logger.info "Topic: #{topic}"
+			options = msg.match[2]
+			@robot.logger.info "options: #{options}"
+			# @robot.logger.info createPoll
+			# response = createPoll topic, options
+			@robot.logger.info "Creating poll with #{topic}"
+			id = ""
+			possibleValues = "0123456789abcdef"
+			id += possibleValues.charAt(Math.floor(Math.random() * possibleValues.length)) for [1..5]
+			pollOptions = (options.split "option: ")[1..]
+			@robot.logger.info "We have #{pollOptions.length()} options"
+			@robot.brain.data.poll[id].topic = topic
+			optionsString = ""

-		for pollOption in pollOptions
-			index = pollOptions.indexOf(pollOption)
-			robot.brain.data.poll[id].option[index].text
-			optionsString += "\t#{index}: #{pollOption}\n"
-		@robot.brain.save()
-		@robot.logger.info "Brain saved"
+			for pollOption in pollOptions
+				index = pollOptions.indexOf(pollOption)
+				robot.brain.data.poll[id].option[index].text
+				optionsString += "\t#{index}: #{pollOption}\n"
+			@robot.brain.save()
+			@robot.logger.info "Brain saved"

-		text =  """
-				POLL ID: #{id}
-				Topic: #{topic}
-				Options:
-				#{optionsString}
-				"""
-		msg.send "@channel: #{text}"
+			text =  """
+					POLL ID: #{id}
+					Topic: #{topic}
+					Options:
+					#{optionsString}
+					"""
+			msg.send "@channel: #{text}"
+		catch error
+			msg.send error
+			@robot.logger.info error
+
+

 	robot.respond /poll ping/i, (msg) ->
 		@robot.logger.info "ping called"


add missing field to bill object

add missing field to bill object

--- server/models/bill.coffee
+++ server/models/bill.coffee
@@ -6,6 +6,8 @@
     vendor: type: String, default: 'Digital Ocean'
     amount: Number
     plan: String
+    pdfurl: String
+    binaryId: String
     fileId: String


Let Process API do the sending

Let Process API do the sending

--- components/MakeRectangleAspectRatio.coffee
+++ components/MakeRectangleAspectRatio.coffee
@@ -24,13 +24,12 @@
         required: false

     compute = (props) =>
-      return unless @outPorts.rectangle.isAttached()
       return unless @hasAllProps(props)
       inputs = props
       out = @computeRectangle inputs
       out.type = 'rectangle'
       out.point = { type: 'point', x: 0, y: 0 }
-      @outPorts.rectangle.send out
+      return out

     ArrayableHelper @, 'rectangle', ports, {compute}


Improved user.isOutOfOffice() if begin is today.

--- app/assets/javascripts/app/models/user.coffee
+++ app/assets/javascripts/app/models/user.coffee
@@ -119,6 +119,7 @@
     start_time = new Date(Date.parse(start_time))
     end_time = new Date(Date.parse(end_time))
     now = new Date((new Date).toDateString())
+    now.setDate(now.getDate() + 1)
     if start_time <= now && end_time >= now
       return true
     false


Added public board_string creator.

Added public board_string creator.

--- app/assets/javascripts/connect_four.js.coffee
+++ app/assets/javascripts/connect_four.js.coffee
@@ -18,6 +18,14 @@
 	    connect_four.valid_msg "Computer's Turn", ->
 	      add_to_col computer_move(), "black", ->
 	  	    play_game()
+
+connect_four.board_string = ->
+  board = $("canvas#board")
+  all = ("n" for i in [1..board.width()/100] for j in [1..board.height()/100])
+  $(".checker").each (index,element) ->
+    [x,y] = element.id.split("pos")[1].split("_")
+    all[y][x] = if $(this).hasClass("red") then "r" else "b"
+  all.join(";")

 check_board = (color) ->
   all_checkers = []


quote the commit message

quote the commit message

--- src/repo.coffee
+++ src/repo.coffee
@@ -203,7 +203,7 @@
   #
   commit: (message, options, callback) ->
     [options, callback] = [callback, options] if !callback
-    options = _.extend options, {m: message}
+    options = _.extend options, {m: "'#{message}'"}
     @git "commit", options, (err, stdout, stderr) ->
       callback err


(cleanup) Remove uneccessary logs.

(cleanup) Remove uneccessary logs.

--- src/rest.coffee
+++ src/rest.coffee
@@ -23,7 +23,6 @@
       (app, config) ->
         app.get rest.path, (req,res) ->
           rest.dataCall(req.params[rest.param]).then (file) ->
-            console.log("getting file " + file)
             res.sendFile file
     postByBodyParam: (rest) ->
       (app, config) ->


fixed bug

fixed bug

--- app/lib/collections/schemas/_milestone.coffee
+++ app/lib/collections/schemas/_milestone.coffee
@@ -1,4 +1,4 @@
-schema = SimpleSchema
+schema = new SimpleSchema
   name:
     type: String
     label: 'Name'


Allow to set custom vars for ga tracker.


Added cfml extension as well.

Added cfml extension as well.

--- src/sloc.coffee
+++ src/sloc.coffee
@@ -204,7 +204,7 @@
   "c"
   "cc"
   "cfc"
-  "cfm"
+  "cfm", "cfml"
   "clj"
   "cljs"
   "coffee"


Handle decoding errors

Handle decoding errors

--- src/sona.coffee
+++ src/sona.coffee
@@ -29,11 +29,15 @@
     request.onload = =>
       @context.decodeAudioData request.response, (buffer) =>
         @buffers[source.id] = buffer
-
-        if @sources.length then @load callback
-        else if typeof callback is 'function' then callback()
+        @next callback
+      , (e) =>
+        @next callback

     request.send()
+
+  next: (callback) ->
+    if @sources.length then @load callback
+    else if typeof callback is 'function' then callback()

   play: (id, _loop = false) ->
     return if not @supported or @buffers[id] is undefined
@@ -70,14 +74,6 @@
     return if not @supported or @sounds[id] is undefined
     @sounds[id].gainNode.gain.value = volume

-  getPosition: (id) ->
-    return if not @supported or @buffers[id] is undefined
-    # pass
-
-  setPosition: (id) ->
-    return if not @supported or @buffers[id] is undefined
-    # pass
-
 if typeof exports != 'undefined'
   module.exports = Sona
 else


Fix renaming of read-only documents [#113638019]

--- src/code/providers/readonly-provider.coffee
+++ src/code/providers/readonly-provider.coffee
@@ -47,7 +47,9 @@
   list: (metadata, callback) ->
     @_loadTree (err, tree) =>
       return callback err if err
-      callback null, if metadata?.type is CloudMetadata.Folder then metadata.providerData.children else @tree
+      items = if metadata?.type is CloudMetadata.Folder then metadata.providerData.children else @tree
+      # clone the metadata items so that any changes made to the filename or content in the edit is not cached
+      callback null, _.map items, (item) -> _.clone item

   canOpenSaved: -> false


More recognisable time format

More recognisable time format

--- options/defaults/output.cson
+++ options/defaults/output.cson
@@ -17,7 +17,7 @@
         # {2} = minute
         # {3} = second
         # {4} = a/p
-        format: "{0}:{2}:{3}"
+        format: "{1}:{2}:{3}{4}"
         am: "AM"
         pm: "PM"


striped incorrect for further differentiation for color-blindness

--- src/components/task-plan/reading-stats.cjsx
+++ src/components/task-plan/reading-stats.cjsx
@@ -42,6 +42,7 @@

     classes = 'reading-progress-bar'
     classes += ' no-progress' unless percent
+    classes += ' progress-bar-striped' if correctOrIncorrect is 'incorrect'

     label = "#{percent}%"
     label = "#{label} #{correctOrIncorrect}" if percent is 100


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/active_bounds.coffee
+++ test/active_bounds.coffee
@@ -1,4 +1,6 @@
 module "ActiveBounds"
+
+App.

 test "should remove objects outside of activeBounds", 2, ->
   obj = GameObject


Fix tests for lingering promise in before action filters

--- test/spec/dispatcher_spec.coffee
+++ test/spec/dispatcher_spec.coffee
@@ -546,10 +546,10 @@
         dispatcher.executeBeforeActionChain controller, 'user_manager',
           'index', params, options

-        expect(loadSession).was.calledWith params, options
+        expect(loadSession).was.calledWith params
         expect(checkAdminPrivileges).was.calledWith params, options, userModel
-        expect(loadUsers).was.calledWith params, options
-        expect(indexAction).was.calledWith params, options
+        expect(loadUsers).was.calledWith params
+        expect(indexAction).was.calledWith params

         expect(checkAdminPrivileges.firstCall.args[2]).to.be userModel

@@ -674,3 +674,47 @@
         args = action.firstCall.args
         expect(args[0]).to.eql params
         expect(args[1]).to.eql expectedOptions
+
+      it 'should not call a deferred callback upon a new route being fired with a different controller', (done) ->
+        deferred = $.Deferred()
+        promise = deferred.promise()
+        route1 = controller: 'test_stalled_before_actions', action: 'show'
+        route2 = controller: 'test_before_actions', action: 'index'
+
+        # First order controller
+        class TestStalledBeforeActionsController extends Controller
+
+          beforeAction:
+            '.*': ->
+              promise
+            show: ->
+              console.log 'show'
+              null
+
+          show: ->
+            console.log 'show action'
+
+        # Spies
+        proto = TestBeforeActionsController.prototype
+        indexActionSpy = sinon.spy proto, 'index'
+        proto = TestStalledBeforeActionsController.prototype
+        beforeActionSpy = sinon.spy proto.beforeAction, 'show'
+        # Define a test controller AMD module
+        testStalledBeforeActionsModule = 'controllers/test_stalled_before_actions_controller'
+        define testStalledBeforeActionsModule, -> TestStalledBeforeActionsController
+        # Helpers for asynchronous tests
+        loadStalledBeforeActionsController = (callback) ->
+          require [testStalledBeforeActionsModule], callback
+
+        mediator.publish 'matchRoute', route1, params, options
+        loadStalledBeforeActionsController ->
+          mediator.publish 'matchRoute', route2, params, options
+          loadBeforeActionsController ->
+            expect(indexActionSpy).was.called()
+
+            deferred.resolve()
+            expect(beforeActionSpy).was.notCalled()
+
+            beforeActionSpy.restore()
+            indexActionSpy.restore()
+            done()


Better syntax and typo fix

Better syntax and typo fix

--- src/whip.coffee
+++ src/whip.coffee
@@ -23,7 +23,7 @@
   get: (ident) ->
     if ident of @scope
       @scope[ident]
-    else if @parent isnt undefined
+    else if @parent?
       @parent.get ident

   # #### Set
@@ -33,7 +33,7 @@
   #
   # This method is only used by the core library function `def`.
   set: (ident, value) ->
-    if @parnet is undefined
+    if @parent is undefined
       @scope[ident] = value
     else
       @parent.set ident, value


Add some tests for the string parsing.

Add some tests for the string parsing.

--- test/reporter.spec.coffee
+++ test/reporter.spec.coffee
@@ -132,6 +132,26 @@
       reporter.onBrowserComplete fakeChrome, undefined
       expect(mockAdd).not.to.have.been.called

+    it 'collects coverage data', ->
+      result =
+        coverage:
+          "fileA.js": [4, 5, 6]
+          "fileB.js": [3, 4, 5]
+      parsedValue =
+        "fileA.js": [4, 5, 6]
+        "fileB.js": [3, 4, 5]
+      reporter.onBrowserComplete fakeChrome, result
+      expect(mockAdd.lastCall.args[0]).to.deep.equal parsedValue
+
+    it 'parses string results before collecting', ->
+      result =
+        coverage: '{"file1.js":[4, 5, 6],"file2.js":[3, 4, 5]}'
+      parsedValue =
+        "file1.js": [4, 5, 6]
+        "file2.js": [3, 4, 5]
+      reporter.onBrowserComplete fakeChrome, result
+      expect(mockAdd.lastCall.args[0]).to.deep.equal parsedValue
+
     it 'should make reports', ->
       reporter.onRunComplete browsers
       expect(mockMkdir).to.have.been.calledTwice


opt: try catch

opt: try catch

--- src/yaku.coffee
+++ src/yaku.coffee
@@ -147,6 +147,8 @@
 	$groupNum = 5

 	$circularErrorInfo = 'circular promise resolution chain'
+
+	$tryErr = {}

 	# ************************* Private Constant End **************************

@@ -220,28 +222,11 @@
 	resolveValue = (x, resolve, reject) ->
 		type = typeof x
 		if x != null and (type == 'function' or type == 'object')
-			try
-				xthen = x.then
-			catch e
-				reject e
-				return
+			xthen = getXthen x, reject
+			return if xthen == $tryErr

 			if typeof xthen == 'function'
-				# TODO: If the promise is a Yaku instance,
-				# not some thing like the Bluebird or jQuery Defer,
-				# we can do some performance optimization.
-				try
-					isResolved = false
-					xthen.call x, (y) ->
-						return if isResolved
-						isResolved = true
-						resolveValue y, resolve, reject
-					, (r) ->
-						return if isResolved
-						isResolved = true
-						reject r
-				catch e
-					reject e if not isResolved
+				resolveXthen x, xthen, resolve, reject
 			else
 				resolve x
 		else
@@ -249,6 +234,37 @@

 		return

+	resolveXthen = (x, xthen, resolve, reject) ->
+		# TODO: If the promise is a Yaku instance,
+		# not some thing like the Bluebird or jQuery Defer,
+		# we can do some performance optimization.
+		try
+			isResolved = false
+			xthen.call x, (y) ->
+				return if isResolved
+				isResolved = true
+				resolveValue y, resolve, reject
+			, (r) ->
+				return if isResolved
+				isResolved = true
+				reject r
+		catch e
+			reject e if not isResolved
+
+	getXthen = (x, reject) ->
+		try
+			x.then
+		catch e
+			reject e
+			return $tryErr
+
+	getX = (self, offset, handler) ->
+		try
+			handler self._value
+		catch e
+			self[offset + 3] e
+			return $tryErr
+
 	###*
 	 * Decide how handlers works.
 	 * @private
@@ -261,11 +277,8 @@
 		handler = self[offset + self._state]

 		if typeof handler == 'function'
-			try
-				x = handler self._value
-			catch e
-				self[offset + 3] e
-				return
+			x = getX self, offset, handler
+			return if x == $tryErr

 			# Prevent circular chain.
 			if x == self[offset + 4] and x


Use the helper

Use the helper

--- spec/UrlMiddleware.coffee
+++ spec/UrlMiddleware.coffee
@@ -68,7 +68,7 @@
     it 'should send application:redirect action', (done) ->
       checkRedirect = (data) ->
         chai.expect(data).to.eql '#gist/abc123'
-      receiveAction newAction, 'application:redirect', checkRedirect, done
+      mw.receiveAction newAction, 'application:redirect', checkRedirect, done
       window.location.hash = '#example/abc123'
   describe 'on hash change to an gist URL', ->
     it 'should send github:gist action', (done) ->
@@ -81,5 +81,5 @@
           component: null
           nodes: []
           remote: []
-      receiveAction newAction, 'github:gist', checkOpen, done
+      mw.receiveAction newAction, 'github:gist', checkOpen, done
       window.location.hash = '#gist/abc123'


Update spec

Update spec

--- spec/app/atom-spec.coffee
+++ spec/app/atom-spec.coffee
@@ -340,7 +340,10 @@
         results = docRunner.argsForCall[0][1].split("\n")
         results.pop()

-        coverage = parseFloat _.last(results).match(/.+?%/)
+        errors = parseInt results.pop().match(/\d+/)
+        expect(errors).toBe 0
+
+        coverage = parseFloat results.pop().match(/.+?%/)
         expect(coverage).toBeGreaterThan 85

         # stderr
@@ -359,7 +362,10 @@
         results = docRunner.argsForCall[0][1].split("\n")
         results.pop()

-        coverage = parseFloat _.last(results).match(/.+?%/)
+        errors = parseInt results.pop().match(/\d+/)
+        expect(errors).toBe 0
+
+        coverage = parseFloat results.pop().match(/.+?%/)
         expect(coverage).toBeGreaterThan 85

         # stderr


Add basic C, C++, Objective-C, and Objective-C++ specs

--- spec/grammars-spec.coffee
+++ spec/grammars-spec.coffee
@@ -15,3 +15,47 @@
         expect(commandContext.command).toBeDefined()
         argList = commandContext.args(@codeContext)
         expect(argList).toBeDefined()
+
+  describe 'C', ->
+    it 'returns the "xcrun" File Based runner on Mac OS X', ->
+      grammar = grammarMap['C']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner.command).toEqual('xcrun')
+
+    it 'is not defined on other operating systems', ->
+      grammar = grammarMap['C']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner).toBe(undefined)
+
+  describe 'C++', ->
+    it 'returns the "xcrun" File Based runner on Mac OS X', ->
+      grammar = grammarMap['C++']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner.command).toEqual('xcrun')
+
+    it 'is not defined on other operating systems', ->
+      grammar = grammarMap['C++']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner).toBe(undefined)
+
+  describe 'Objective-C', ->
+    it 'returns the "xcrun" File Based runner on Mac OS X', ->
+      grammar = grammarMap['Objective-C']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner.command).toEqual('xcrun')
+
+    it 'is not defined on other operating systems', ->
+      grammar = grammarMap['Objective-C']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner).toBe(undefined)
+
+  describe 'Objective-C++', ->
+    it 'returns the "xcrun" File Based runner on Mac OS X', ->
+      grammar = grammarMap['Objective-C++']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner.command).toEqual('xcrun')
+
+    it 'is not defined on other operating systems', ->
+      grammar = grammarMap['Objective-C++']
+      fileBasedRunner = grammar['File Based']
+      expect(fileBasedRunner).toBe(undefined)


updating docs

updating docs

--- t+.coffee
+++ t+.coffee
@@ -26,7 +26,7 @@
 #     * Content between blocks in child template will be ignored
 #   * Interpreted templates cached for fast re-render
 # * Simple template management via `t.put(name, template, callback)` and `t.load(name, callback)`
-#   * Extensible - simply overwrite `t.put` & `t.load` with your own logic and pass an instance of `t` when calling 'callback'.
+#   * Extensible - simply overwrite `t.put` & `t.load` with your own logic and pass an instance of `t` when calling `callback`.
 #   * Register functions should expect `(name, template, callback)`, while loader functions should accept `name` and pass template to `callback`.
 # * Macros
 #   * Inline: `{{+<name>(param1, param2...)}}`. If an error occurs, returns `''`.


Update welcome.cson

Update welcome.cson

for samenessing. packages is not "плагины", because everywhere in Atom it word sayd like a "расширения".

--- def/ru/welcome.cson
+++ def/ru/welcome.cson
@@ -22,7 +22,7 @@
     atomOrg: {
       text1: ""
       link: "Atom org"
-      text2: ". Здесь находятся все плагины, созданные на GitHub."
+      text2: ". Здесь находятся все расширения, созданные на GitHub."
       _template: "${text1}<a>${link}</a>${text2}"
     }
   }


Add core.fileSystemWatcher translation

Add core.fileSystemWatcher translation

--- def/settings.coffee
+++ def/settings.coffee
@@ -133,6 +133,16 @@
         desc: "Encodage des caractères à utiliser par défaut lors de la lecture et de l'écriture de fichiers."
       }
       {
+        id: 'core.fileSystemWatcher'
+        title: "Surveillance de système de fichiers"
+        desc: "Choisi l'implémentation sous-jacente utilisé pour surveiller les changements de système de fichiers. Émuler les changements ne captuera aucun évenement causé par d'autres applications que Atom mais aidera à éviter les plantages et les gels."
+        select:
+          native: "API de la plateforme actuel"
+          experimental: "Surveillance de système de fichiers expérimental"
+          poll: "Vote"
+          atom: "Émuler avec les évenements d'Atom"
+      }
+      {
         id: 'core.followSymlinks'
         title: "Utiliser les liens symboliques"
         desc: "Utilise les liens symboliques lors de la recherche et de l'ouverture de fichiers à l'aide de Fuzzy Finder."


Adde newline to end of file

Adde newline to end of file


Whitespace

Whitespace

--- spec/arrayMethods.coffee
+++ spec/arrayMethods.coffee
@@ -22,7 +22,6 @@

     it 'fails given an object', ->
       Z({}).filter((x) -> x).should.be.rejected
-

   describe 'join', ->

@@ -93,6 +92,7 @@
       Z("foobar").keys().should.be.rejected

+
 describe 'underscore method each', ->

   describe 'keys', ->
@@ -108,4 +108,3 @@

     it 'turns the value into a string', ->
       Z(1).toString().should.become "1"
-


Fix console.warning -> console.warn typo

--- app/views/editor/verifier/VerifierTest.coffee
+++ app/views/editor/verifier/VerifierTest.coffee
@@ -94,7 +94,7 @@
     return true

   onUserCodeProblem: (e) ->
-    console.warning "Found user code problem:", e
+    console.warn "Found user code problem:", e

   onNonUserCodeProblem: (e) ->
     console.error "Found non-user-code problem:", e


Add Persian locale (فارسی)

Add Persian locale (فارسی)

--- tests/locales.test.coffee
+++ tests/locales.test.coffee
@@ -350,3 +350,16 @@

     it "shows the correct CONFIRM translation", ->
       expect(@labels.confirm).to.equal "ยืนยัน"
+
+  describe "Persian", ->
+    beforeEach ->
+      @setLocale "fa"
+
+    it "shows the correct OK translation", ->
+      expect(@labels.ok).to.equal "قبول"
+
+    it "shows the correct CANCEL translation", ->
+      expect(@labels.cancel).to.equal "لغو"
+
+    it "shows the correct CONFIRM translation", ->
+      expect(@labels.confirm).to.equal "تایید"


WIP: removing noise

WIP: removing noise

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -1,7 +1,7 @@
 helpers = require './spec-helper'
 _ = require 'underscore-plus'

-fdescribe "Motions", ->
+describe "Motions", ->
   [editor, editorElement, vimState] = []

   beforeEach ->
@@ -34,19 +34,6 @@
     inputEditor = editor.normalModeInputView.editorElement
     inputEditor.getModel().setText(text)
     atom.commands.dispatch(inputEditor, "core:confirm")
-
-  set = (options={}) ->
-    if options.keystroke?
-      keystroke(options.keystroke)
-    if options.text?
-      editor.setText(options.text)
-    if options.cursor?
-      editor.setCursorScreenPosition options.cursor
-    if options.addCursor?
-      editor.addCursorAtBufferPosition options.addCursor
-    if options.register?
-      vimState.register.set '"', text: options.register
-

   selectedScreenRange = ->
     expect editor.getSelectedScreenRange()
@@ -57,13 +44,46 @@
   selectedBufferRanges = ->
     expect editor.getSelectedBufferRanges()

+  set = (options={}) ->
+    if options.keystroke?
+      keystroke(options.keystroke)
+    if options.text?
+      editor.setText(options.text)
+    if options.cursor?
+      editor.setCursorScreenPosition options.cursor
+    if options.cursorBuffer?
+      editor.setCursorBufferPosition options.cursorBuffer
+    if options.addCursor?
+      editor.addCursorAtBufferPosition options.addCursor
+    if options.register?
+      vimState.register.set '"', text: options.register
+
   ensure = (_keystroke, options={}) ->
+    # input
     unless _.isEmpty(_keystroke)
-      keystroke(_keystroke)
+      if _.isArray(_keystroke)
+        for k in _keystroke
+          if _.isString(k)
+            keystroke(k)
+          else
+            if k.normal?
+              submitNormalModeInputText k.normal
+            else if k.normalChar?
+              normalModeInputKeydown k.normalChar
+            else if k.ctrl?
+              keydown k.ctrl, ctrl: true
+      else
+        keystroke(_keystroke)
+
+    # validate
+    # [NOTE] Order is important.
+    # e.g. Text need to be set before changing cursor position.
     if options.text?
       expect(editor.getText()).toBe options.text
     if options.cursor?
       expect(editor.getCursorScreenPosition()).toEqual options.cursor
+    if options.cursorBuffer?
+      expect(editor.getCursorBufferPosition()).toEqual options.cursorBuffer
     if options.register?
       expect(vimState.register.get('"').text).toBe options.register
     if options.selectedText?
@@ -73,6 +93,8 @@
       selectedBufferRange().toEqual options.selectedBufferRange
     if options.selectedBufferRanges?
       selectedBufferRanges().toEqual options.selectedBufferRanges
+    if options.scrollTop?
+      expect(editor.getScrollTop()).toEqual options.scrollTop

     if options.selectedScreenRange?
       selectedScreenRange().toEqual options.selectedScreenRange
@@ -645,6 +667,7 @@
             cursor: [1, 0]

   describe "the enter keybinding", ->
+    # [FIXME] Dirty test, whats this!?
     keydownCodeForEnter = '\r' # 'enter' does not work
     startingText = "  abc\n  abc\nabcdefg\n"

@@ -654,13 +677,14 @@
       describe "as a motion", ->
         it "acts the same as the + keybinding", ->
           # do it with + and save the results
-          editor.setText(startingText)
-          editor.setCursorScreenPosition(startingCursorPosition)
+          set
+            text: startingText
+            cursor: startingCursorPosition
           keydown('+')
           referenceCursorPosition = editor.getCursorScreenPosition()
-          # do it again with enter and compare the results
-          editor.setText(startingText)
-          editor.setCursorScreenPosition(startingCursorPosition)
+          set
+            text: startingText
+            cursor: startingCursorPosition
           keydown(keydownCodeForEnter)
           expect(editor.getCursorScreenPosition()).toEqual referenceCursorPosition

@@ -683,146 +707,98 @@

   describe "the gg keybinding", ->
     beforeEach ->
-      editor.setText(" 1abc\n 2\n3\n")
-      editor.setCursorScreenPosition([0, 2])
+      set
+        text: " 1abc\n 2\n3\n"
+        cursor: [0, 2]

     describe "as a motion", ->
       describe "in normal mode", ->
-        beforeEach ->
-          keydown('g')
-          keydown('g')
-
         it "moves the cursor to the beginning of the first line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+          ensure 'gg', cursor: [0, 0]

       describe "in linewise visual mode", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([1, 0])
-          vimState.activateVisualMode('linewise')
-          keydown('g')
-          keydown('g')
-
         it "selects to the first line in the file", ->
-          expect(editor.getSelectedText()).toBe " 1abc\n 2\n"
-
-        it "moves the cursor to a specified line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+          set cursor: [1, 0]
+          ensure 'Vgg',
+            selectedText: " 1abc\n 2\n"
+            cursor: [0, 0]

       describe "in characterwise visual mode", ->
         beforeEach ->
-          editor.setCursorScreenPosition([1, 1])
-          vimState.activateVisualMode()
-          keydown('g')
-          keydown('g')
-
+          set cursor: [1, 1]
         it "selects to the first line in the file", ->
-          expect(editor.getSelectedText()).toBe "1abc\n 2"
-
-        it "moves the cursor to a specified line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+          ensure 'vgg',
+            selectedText: "1abc\n 2"
+            cursor: [0, 1]

     describe "as a repeated motion", ->
       describe "in normal mode", ->
-        beforeEach ->
-          keydown('2')
-          keydown('g')
-          keydown('g')
-
         it "moves the cursor to a specified line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure '2gg', cursor: [1, 0]

       describe "in linewise visual motion", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([2, 0])
-          vimState.activateVisualMode('linewise')
-          keydown('2')
-          keydown('g')
-          keydown('g')
-
         it "selects to a specified line", ->
-          expect(editor.getSelectedText()).toBe " 2\n3\n"
-
-        it "moves the cursor to a specified line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          set cursor: [2, 0]
+          ensure 'V2gg',
+            selectedText: " 2\n3\n"
+            cursor: [1, 0]

       describe "in characterwise visual motion", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([2, 0])
-          vimState.activateVisualMode()
-          keydown('2')
-          keydown('g')
-          keydown('g')
-
         it "selects to a first character of specified line", ->
-          expect(editor.getSelectedText()).toBe "2\n3"
-
-        it "moves the cursor to a specified line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 1]
+          set cursor: [2, 0]
+          ensure 'v2gg',
+            selectedText: "2\n3"
+            cursor: [1, 1]

   describe "the g_ keybinding", ->
     beforeEach ->
-      editor.setText("1  \n    2  \n 3abc\n ")
+      set text: "1  \n    2  \n 3abc\n "

     describe "as a motion", ->
       it "moves the cursor to the last nonblank character", ->
-        editor.setCursorScreenPosition([1, 0])
-        keydown('g')
-        keydown('_')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 4]
+        set cursor: [1, 0]
+        ensure 'g_', cursor: [1, 4]

       it "will move the cursor to the beginning of the line if necessary", ->
-        editor.setCursorScreenPosition([0, 2])
-        keydown('g')
-        keydown('_')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+        set cursor: [0, 2]
+        ensure 'g_', cursor: [0, 0]

     describe "as a repeated motion", ->
       it "moves the cursor downward and outward", ->
-        editor.setCursorScreenPosition([0, 0])
-        keydown('2')
-        keydown('g')
-        keydown('_')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 4]
+        set cursor: [0, 0]
+        ensure '2g_', cursor: [1, 4]

     describe "as a selection", ->
       it "selects the current line excluding whitespace", ->
-        editor.setCursorScreenPosition([1, 2])
-        vimState.activateVisualMode()
-        keydown('2')
-        keydown('g')
-        keydown('_')
-        expect(editor.getSelectedText()).toEqual "  2  \n 3abc"
+        set cursor: [1, 2]
+        ensure 'v2g_',
+          selectedText: "  2  \n 3abc"

   describe "the G keybinding", ->
     beforeEach ->
-      editor.setText("1\n    2\n 3abc\n ")
-      editor.setCursorScreenPosition([0, 2])
-
-    describe "as a motion", ->
-      beforeEach -> keydown('G', shift: true)
-
+      set
+        text: "1\n    2\n 3abc\n "
+        cursor: [0, 2]
+
+    describe "as a motion", ->
       it "moves the cursor to the last line after whitespace", ->
-        expect(editor.getCursorScreenPosition()).toEqual [3, 0]
+        ensure 'G', cursor: [3, 0]

     describe "as a repeated motion", ->
-      beforeEach ->
-        keydown('2')
-        keydown('G', shift: true)
-
       it "moves the cursor to a specified line", ->
-        expect(editor.getCursorScreenPosition()).toEqual [1, 4]
+        ensure '2G', cursor: [1, 4]

     describe "as a selection", ->
       beforeEach ->
+        set cursor: [1, 0]
         editor.setCursorScreenPosition([1, 0])
         vimState.activateVisualMode()
         keydown('G', shift: true)

       it "selects to the last line in the file", ->
-        expect(editor.getSelectedText()).toBe "    2\n 3abc\n "
-
-      it "moves the cursor to the last line after whitespace", ->
-        expect(editor.getCursorScreenPosition()).toEqual [3, 1]
+        ensure 'vG',
+          selectedText: "    2\n 3abc\n "
+          cursor: [3, 1]

   describe "the / keybinding", ->
     pane = null
@@ -831,8 +807,9 @@
       pane = {activate: jasmine.createSpy("activate")}
       spyOn(atom.workspace, 'getActivePane').andReturn(pane)

-      editor.setText("abc\ndef\nabc\ndef\n")
-      editor.setCursorBufferPosition([0, 0])
+      set
+        text: "abc\ndef\nabc\ndef\n"
+        cursor: [0, 0]

       # clear search history
       vimState.globalVimState.searchHistory = []
@@ -840,58 +817,39 @@

     describe "as a motion", ->
       it "moves the cursor to the specified search pattern", ->
-        keydown('/')
-
-        submitNormalModeInputText 'def'
-
-        expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+        ensure ['/', normal: 'def'],
+          cursor: [1, 0]
         expect(pane.activate).toHaveBeenCalled()

       it "loops back around", ->
-        editor.setCursorBufferPosition([3, 0])
-        keydown('/')
-        submitNormalModeInputText 'def'
-
-        expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+        set cursor: [3, 0]
+        ensure ['/', normal: 'def'],
+          cursor: [1, 0]

       it "uses a valid regex as a regex", ->
-        keydown('/')
         # Cycle through the 'abc' on the first line with a character pattern
-        submitNormalModeInputText '[abc]'
-        expect(editor.getCursorBufferPosition()).toEqual [0, 1]
-        keydown('n')
-        expect(editor.getCursorBufferPosition()).toEqual [0, 2]
+        ensure ['/', normal: '[abc]'], cursor: [0, 1]
+        ensure 'n', cursor: [0, 2]

       it "uses an invalid regex as a literal string", ->
         # Go straight to the literal [abc
-        editor.setText("abc\n[abc]\n")
-        keydown('/')
-        submitNormalModeInputText '[abc'
-        expect(editor.getCursorBufferPosition()).toEqual [1, 0]
-        keydown('n')
-        expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+        set text: "abc\n[abc]\n"
+        ensure ['/', normal: '[abc'], cursor: [1, 0]
+        ensure 'n', cursor: [1, 0]

       it "uses ? as a literal string", ->
-        editor.setText("abc\n[a?c?\n")
-        keydown('/')
-        submitNormalModeInputText '?'
-        expect(editor.getCursorBufferPosition()).toEqual [1, 2]
-        keydown('n')
-        expect(editor.getCursorBufferPosition()).toEqual [1, 4]
+        set text: "abc\n[a?c?\n"
+        ensure ['/', normal: '?'], cursor: [1, 2]
+        ensure 'n', cursor: [1, 4]

       it 'works with selection in visual mode', ->
-        editor.setText('one two three')
-        keydown('v')
-        keydown('/')
-        submitNormalModeInputText 'th'
-        expect(editor.getCursorBufferPosition()).toEqual [0, 9]
-        keydown('d')
-        expect(editor.getText()).toBe 'hree'
+        set text: 'one two three'
+        ensure ['v/', normal: 'th'], cursor: [0, 9]
+        ensure 'd', text: 'hree'

       it 'extends selection when repeating search in visual mode', ->
-        editor.setText('line1\nline2\nline3')
-        keydown('v')
-        keydown('/')
+        set text: 'line1\nline2\nline3'
+        keystroke 'v/'
         submitNormalModeInputText 'line'
         {start, end} = editor.getSelectedBufferRange()
         expect(start.row).toEqual 0
@@ -903,50 +861,38 @@

       describe "case sensitivity", ->
         beforeEach ->
-          editor.setText("\nabc\nABC\n")
-          editor.setCursorBufferPosition([0, 0])
-          keydown('/')
+          set
+            text: "\nabc\nABC\n"
+            cursor: [0, 0]

         it "works in case sensitive mode", ->
-          submitNormalModeInputText 'ABC'
-          expect(editor.getCursorBufferPosition()).toEqual [2, 0]
-          keydown('n')
-          expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+          ensure ['/', normal: 'ABC'], cursor: [2, 0]
+          ensure 'n', cursor: [2, 0]

         it "works in case insensitive mode", ->
-          submitNormalModeInputText '\\cAbC'
-          expect(editor.getCursorBufferPosition()).toEqual [1, 0]
-          keydown('n')
-          expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+          ensure ['/', normal: '\\cAbC'], cursor: [1, 0]
+          ensure 'n', cursor: [2, 0]

         it "works in case insensitive mode wherever \\c is", ->
-          submitNormalModeInputText 'AbC\\c'
-          expect(editor.getCursorBufferPosition()).toEqual [1, 0]
-          keydown('n')
-          expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+          ensure ['/', normal: 'AbC\\c'], cursor: [1, 0]
+          ensure 'n', cursor: [2, 0]

         it "uses case insensitive search if useSmartcaseForSearch is true and searching lowercase", ->
           atom.config.set 'vim-mode.useSmartcaseForSearch', true
-          submitNormalModeInputText 'abc'
-          expect(editor.getCursorBufferPosition()).toEqual [1, 0]
-          keydown('n')
-          expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+          ensure ['/', normal: 'abc'], cursor: [1, 0]
+          ensure 'n', cursor: [2, 0]

         it "uses case sensitive search if useSmartcaseForSearch is true and searching uppercase", ->
           atom.config.set 'vim-mode.useSmartcaseForSearch', true
-          submitNormalModeInputText 'ABC'
-          expect(editor.getCursorBufferPosition()).toEqual [2, 0]
-          keydown('n')
-          expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+          ensure ['/', normal: 'ABC'], cursor: [2, 0]
+          ensure 'n', cursor: [2, 0]

       describe "repeating", ->
         it "does nothing with no search history", ->
-          editor.setCursorBufferPosition([0, 0])
-          keydown('n')
-          expect(editor.getCursorBufferPosition()).toEqual [0, 0]
-          editor.setCursorBufferPosition([1, 1])
-          keydown('n')
-          expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+          set cursor: [0, 0]
+          ensure 'n', cursor: [0, 0]
+          set cursor: [1, 1]
+          ensure 'n', cursor: [1, 1]

       describe "repeating with search history", ->
         beforeEach ->
@@ -954,98 +900,66 @@
           submitNormalModeInputText 'def'

         it "repeats previous search with /<enter>", ->
-          keydown('/')
-          submitNormalModeInputText('')
-          expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+          ensure ['/', normal: ''], cursor: [3, 0]

         it "repeats previous search with //", ->
-          keydown('/')
-          submitNormalModeInputText('/')
-          expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+          ensure ['/', normal: '/'], cursor: [3, 0]

         describe "the n keybinding", ->
           it "repeats the last search", ->
-            keydown('n')
-            expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+            ensure 'n', cursor: [3, 0]

         describe "the N keybinding", ->
           it "repeats the last search backwards", ->
-            editor.setCursorBufferPosition([0, 0])
-            keydown('N', shift: true)
-            expect(editor.getCursorBufferPosition()).toEqual [3, 0]
-            keydown('N', shift: true)
-            expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+            set cursor: [0, 0]
+            ensure 'N', cursor: [3, 0]
+            ensure 'N', cursor: [1, 0]

       describe "composing", ->
         it "composes with operators", ->
-          keydown('d')
-          keydown('/')
-          submitNormalModeInputText('def')
-          expect(editor.getText()).toEqual "def\nabc\ndef\n"
+          ensure ['d/', normal: 'def'], text: "def\nabc\ndef\n"

         it "repeats correctly with operators", ->
-          keydown('d')
-          keydown('/')
-          submitNormalModeInputText('def')
-
-          keydown('.')
-          expect(editor.getText()).toEqual "def\n"
+          ensure ['d/', normal: 'def', '.'],
+            text: "def\n"

     describe "when reversed as ?", ->
       it "moves the cursor backwards to the specified search pattern", ->
-        keydown('?')
-        submitNormalModeInputText('def')
-        expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+        ensure ['?', normal: 'def'], cursor: [3, 0]

       it "accepts / as a literal search pattern", ->
-        editor.setText("abc\nd/f\nabc\nd/f\n")
-        editor.setCursorBufferPosition([0, 0])
-        keydown('?')
-        submitNormalModeInputText('/')
-        expect(editor.getCursorBufferPosition()).toEqual [3, 1]
-        keydown('?')
-        submitNormalModeInputText('/')
-        expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+        set
+          text: "abc\nd/f\nabc\nd/f\n"
+          cursor: [0, 0]
+        ensure ['?', normal: '/'], cursor: [3, 1]
+        ensure ['?', normal: '/'], cursor: [1, 1]

       describe "repeating", ->
         beforeEach ->
-          keydown('?')
-          submitNormalModeInputText('def')
+          ensure ['?', normal: 'def']

         it "repeats previous search as reversed with ?<enter>", ->
-          keydown('?')
-          submitNormalModeInputText('')
-          expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+          ensure ['?', normal: ''], cursor: [1, 0]

         it "repeats previous search as reversed with ??", ->
-          keydown('?')
-          submitNormalModeInputText('?')
-          expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+          ensure ['?', normal: '?'], cursor: [1, 0]

         describe 'the n keybinding', ->
           it "repeats the last search backwards", ->
-            editor.setCursorBufferPosition([0, 0])
-            keydown('n')
-            expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+            set cursor: [0, 0]
+            ensure 'n', cursor: [3, 0]

         describe 'the N keybinding', ->
           it "repeats the last search forwards", ->
-            editor.setCursorBufferPosition([0, 0])
-            keydown('N', shift: true)
-            expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+            set cursor: [0, 0]
+            ensure 'N', cursor: [1, 0]

     describe "using search history", ->
       inputEditor = null

       beforeEach ->
-        keydown('/')
-        submitNormalModeInputText('def')
-        expect(editor.getCursorBufferPosition()).toEqual [1, 0]
-
-        keydown('/')
-        submitNormalModeInputText('abc')
-        expect(editor.getCursorBufferPosition()).toEqual [2, 0]
-
+        ensure ['/', normal: 'def'], cursor: [1, 0]
+        ensure ['/', normal: 'abc'], cursor: [2, 0]
         inputEditor = editor.normalModeInputView.editorElement

       it "allows searching history in the search field", ->
@@ -1239,433 +1153,290 @@

   describe 'the mark keybindings', ->
     beforeEach ->
-      editor.setText('  12\n    34\n56\n')
-      editor.setCursorBufferPosition([0, 1])
+      set
+        text: '  12\n    34\n56\n'
+        cursor: [0, 1]

     it 'moves to the beginning of the line of a mark', ->
-      editor.setCursorBufferPosition([1, 1])
-      keydown('m')
-      normalModeInputKeydown('a')
-      editor.setCursorBufferPosition([0, 0])
-      keydown('\'')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorBufferPosition()).toEqual [1, 4]
+      set cursor: [1, 1]
+      ensure ['m', normalChar: 'a']
+      set cursor: [0, 0]
+      ensure ["'", normalChar: 'a'], cursor: [1, 4]

     it 'moves literally to a mark', ->
-      editor.setCursorBufferPosition([1, 1])
-      keydown('m')
-      normalModeInputKeydown('a')
-      editor.setCursorBufferPosition([0, 0])
-      keydown('`')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+      set cursorBuffer: [1, 1]
+      ensure ['m', normalChar: 'a']
+      set cursorBuffer: [0, 0]
+      ensure ['`', normalChar: 'a'], cursorBuffer: [1, 1]

     it 'deletes to a mark by line', ->
-      editor.setCursorBufferPosition([1, 5])
-      keydown('m')
-      normalModeInputKeydown('a')
-      editor.setCursorBufferPosition([0, 0])
-      keydown('d')
-      keydown('\'')
-      normalModeInputKeydown('a')
-      expect(editor.getText()).toEqual '56\n'
+      set cursorBuffer: [1, 5]
+      ensure ['m', normalChar: 'a']
+      set cursorBuffer: [0, 0]
+
+      ensure ["d'", normalChar: 'a'], text: '56\n'

     it 'deletes before to a mark literally', ->
-      editor.setCursorBufferPosition([1, 5])
-      keydown('m')
-      normalModeInputKeydown('a')
-      editor.setCursorBufferPosition([0, 1])
-      keydown('d')
-      keydown('`')
-      normalModeInputKeydown('a')
-      expect(editor.getText()).toEqual ' 4\n56\n'
+      set cursorBuffer: [1, 5]
+      ensure ['m', normalChar: 'a']
+      set cursorBuffer: [0, 1]
+      ensure ['d`', normalChar: 'a'], text: ' 4\n56\n'

     it 'deletes after to a mark literally', ->
-      editor.setCursorBufferPosition([1, 5])
-      keydown('m')
-      normalModeInputKeydown('a')
-      editor.setCursorBufferPosition([2, 1])
-      keydown('d')
-      keydown('`')
-      normalModeInputKeydown('a')
-      expect(editor.getText()).toEqual '  12\n    36\n'
+      set cursorBuffer: [1, 5]
+      ensure ['m', normalChar: 'a']
+      set cursorBuffer: [2, 1]
+      ensure ['d`', normalChar: 'a'], text: '  12\n    36\n'

     it 'moves back to previous', ->
-      editor.setCursorBufferPosition([1, 5])
-      keydown('`')
-      normalModeInputKeydown('`')
-      editor.setCursorBufferPosition([2, 1])
-      keydown('`')
-      normalModeInputKeydown('`')
-      expect(editor.getCursorBufferPosition()).toEqual [1, 5]
+      set cursorBuffer: [1, 5]
+      ensure ['`', normalChar: '`']
+      set cursorBuffer: [2, 1]
+      ensure ['`', normalChar: '`'], cursorBuffer: [1, 5]

   describe 'the f/F keybindings', ->
     beforeEach ->
-      editor.setText("abcabcabcabc\n")
-      editor.setCursorScreenPosition([0, 0])
+      set
+        text: "abcabcabcabc\n"
+        cursor: [0, 0]

     it 'moves to the first specified character it finds', ->
-      keydown('f')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+      ensure ['f', normalChar: 'c'], cursor: [0, 2]

     it 'moves backwards to the first specified character it finds', ->
-      editor.setCursorScreenPosition([0, 2])
-      keydown('F', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      set cursor: [0, 2]
+      ensure ['F', normalChar: 'a'], cursor: [0, 0]

     it 'respects count forward', ->
-      keydown('2')
-      keydown('f')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+      ensure ['2f', normalChar: 'a'], cursor: [0, 6]

     it 'respects count backward', ->
-      editor.setCursorScreenPosition([0, 6])
-      keydown('2')
-      keydown('F', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      cursor: [0, 6]
+      ensure ['2F', normalChar: 'a'], cursor: [0, 0]

     it "doesn't move if the character specified isn't found", ->
-      keydown('f')
-      normalModeInputKeydown('d')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      ensure ['f', normalChar: 'd'], cursor: [0, 0]

     it "doesn't move if there aren't the specified count of the specified character", ->
-      keydown('1')
-      keydown('0')
-      keydown('f')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      ensure ['10f', normalChar: 'a'], cursor: [0, 0]
       # a bug was making this behaviour depend on the count
-      keydown('1')
-      keydown('1')
-      keydown('f')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      ensure ['11f', normalChar: 'a'], cursor: [0, 0]
       # and backwards now
-      editor.setCursorScreenPosition([0, 6])
-      keydown('1')
-      keydown('0')
-      keydown('F', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
-      keydown('1')
-      keydown('1')
-      keydown('F', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+      set cursor: [0, 6]
+      ensure ['10F', normalChar: 'a'], cursor: [0, 6]
+      ensure ['11F', normalChar: 'a'], cursor: [0, 6]

     it "composes with d", ->
-      editor.setCursorScreenPosition([0, 3])
-      keydown('d')
-      keydown('2')
-      keydown('f')
-      normalModeInputKeydown('a')
-      expect(editor.getText()).toEqual 'abcbc\n'
+      set cursor: [0, 3]
+      ensure ['d2f', normalChar: 'a'], text: 'abcbc\n'

   describe 'the t/T keybindings', ->
     beforeEach ->
-      editor.setText("abcabcabcabc\n")
-      editor.setCursorScreenPosition([0, 0])
+      set
+        text: "abcabcabcabc\n"
+        cursor: [0, 0]

     it 'moves to the character previous to the first specified character it finds', ->
-      keydown('t')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+      ensure ['t', normalChar: 'a'], cursor: [0, 2]
       # or stays put when it's already there
-      keydown('t')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+      ensure ['t', normalChar: 'a'], cursor: [0, 2]

     it 'moves backwards to the character after the first specified character it finds', ->
-      editor.setCursorScreenPosition([0, 2])
-      keydown('T', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+      set cursor: [0, 2]
+      ensure ['T', normalChar: 'a'], cursor: [0, 1]

     it 'respects count forward', ->
-      keydown('2')
-      keydown('t')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+      ensure ['2t', normalChar: 'a'], cursor: [0, 5]

     it 'respects count backward', ->
-      editor.setCursorScreenPosition([0, 6])
-      keydown('2')
-      keydown('T', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+      set cursor: [0, 6]
+      ensure ['2T', normalChar: 'a'], cursor: [0, 1]

     it "doesn't move if the character specified isn't found", ->
-      keydown('t')
-      normalModeInputKeydown('d')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      ensure ['t', normalChar: 'd'], cursor: [0, 0]

     it "doesn't move if there aren't the specified count of the specified character", ->
-      keydown('1')
-      keydown('0')
-      keydown('t')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      ensure ['10t', normalChar: 'd'], cursor: [0, 0]
       # a bug was making this behaviour depend on the count
-      keydown('1')
-      keydown('1')
-      keydown('t')
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      ensure ['11t', normalChar: 'a'], cursor: [0, 0]
       # and backwards now
-      editor.setCursorScreenPosition([0, 6])
-      keydown('1')
-      keydown('0')
-      keydown('T', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
-      keydown('1')
-      keydown('1')
-      keydown('T', shift: true)
-      normalModeInputKeydown('a')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+      set cursor: [0, 6]
+      ensure ['10T', normalChar: 'a'], cursor: [0, 6]
+      ensure ['11T', normalChar: 'a'], cursor: [0, 6]

     it "composes with d", ->
-      editor.setCursorScreenPosition([0, 3])
-      keydown('d')
-      keydown('2')
-      keydown('t')
-      normalModeInputKeydown('b')
-      expect(editor.getText()).toBe 'abcbcabc\n'
+      set cursor: [0, 3]
+      ensure ['d2t', normalChar: 'b'],
+        text: 'abcbcabc\n'

     it "selects character under cursor even when no movement happens", ->
-      editor.setCursorBufferPosition([0, 0])
-      keydown('d')
-      keydown('t')
-      normalModeInputKeydown('b')
-      expect(editor.getText()).toBe 'bcabcabcabc\n'
+      set cursor: [0, 0]
+      ensure ['dt', normalChar: 'b'],
+        text: 'bcabcabcabc\n'

   describe 'the V keybinding', ->
     beforeEach ->
-      editor.setText("01\n002\n0003\n00004\n000005\n")
-      editor.setCursorScreenPosition([1, 1])
+      set
+        text: "01\n002\n0003\n00004\n000005\n"
+        cursor: [1, 1]

     it "selects down a line", ->
-      keydown('V', shift: true)
-      keydown('j')
-      keydown('j')
-      expect(editor.getSelectedText()).toBe "002\n0003\n00004\n"
+      ensure 'Vjj', selectedText: "002\n0003\n00004\n"

     it "selects up a line", ->
-      keydown('V', shift: true)
-      keydown('k')
-      expect(editor.getSelectedText()).toBe "01\n002\n"
+      ensure 'Vk', selectedText: "01\n002\n"

   describe 'the ; and , keybindings', ->
     beforeEach ->
-      editor.setText("abcabcabcabc\n")
-      editor.setCursorScreenPosition([0, 0])
+      set
+        text: "abcabcabcabc\n"
+        cursor: [0, 0]

     it "repeat f in same direction", ->
-      keydown('f')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+      ensure ['f', normalChar: 'c'], cursor: [0, 2]
+      ensure ';', cursor: [0, 5]
+      ensure ';', cursor: [0, 8]

     it "repeat F in same direction", ->
-      editor.setCursorScreenPosition([0, 10])
-      keydown('F', shift: true)
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+      set cursor: [0, 10]
+      ensure ['F', normalChar: 'c'], cursor: [0, 8]
+      ensure ';', cursor: [0, 5]
+      ensure ';', cursor: [0, 2]

     it "repeat f in opposite direction", ->
-      editor.setCursorScreenPosition([0, 6])
-      keydown('f')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+      set cursor: [0, 6]
+      ensure ['f', normalChar: 'c'], cursor: [0, 8]
+      ensure ',', cursor: [0, 5]
+      ensure ',', cursor: [0, 2]
+

     it "repeat F in opposite direction", ->
-      editor.setCursorScreenPosition([0, 4])
-      keydown('F', shift: true)
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+      set cursor: [0, 4]
+      ensure ['F', normalChar: 'c'], cursor: [0, 2]
+      ensure ',', cursor: [0, 5]
+      ensure ',', cursor: [0, 8]

     it "alternate repeat f in same direction and reverse", ->
-      keydown('f')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+      ensure ['f', normalChar: 'c'], cursor: [0, 2]
+      ensure ';', cursor: [0, 5]
+      ensure ',', cursor: [0, 2]

     it "alternate repeat F in same direction and reverse", ->
-      editor.setCursorScreenPosition([0, 10])
-      keydown('F', shift: true)
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+      set cursor: [0, 10]
+      ensure ['F', normalChar: 'c'], cursor: [0, 8]
+      ensure ';', cursor: [0, 5]
+      ensure ',', cursor: [0, 8]

     it "repeat t in same direction", ->
-      keydown('t')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 1]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+      ensure ['t', normalChar: 'c'], cursor: [0, 1]
+      ensure ';', cursor: [0, 4]

     it "repeat T in same direction", ->
-      editor.setCursorScreenPosition([0, 10])
-      keydown('T', shift: true)
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 9]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+      set cursor: [0, 10]
+      ensure ['T', normalChar: 'c'], cursor: [0, 9]
+      ensure ';', cursor: [0, 6]

     it "repeat t in opposite direction first, and then reverse", ->
-      editor.setCursorScreenPosition([0, 3])
-      keydown('t')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 4]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 3]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+      set cursor: [0, 3]
+      ensure ['t', normalChar: 'c'], cursor: [0, 4]
+      ensure ',', cursor: [0, 3]
+      ensure ';', cursor: [0, 4]

     it "repeat T in opposite direction first, and then reverse", ->
-      editor.setCursorScreenPosition([0, 4])
-      keydown('T', shift: true)
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 3]
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 4]
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+      set cursor: [0, 4]
+      ensure ['T', normalChar: 'c'], cursor: [0, 3]
+      ensure ',', cursor: [0, 4]
+      ensure ';', cursor: [0, 3]

     it "repeat with count in same direction", ->
-      editor.setCursorScreenPosition([0, 0])
-      keydown('f')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-      keydown('2')
-      keydown(';')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+      set cursor: [0, 0]
+      ensure ['f', normalChar: 'c'], cursor: [0, 2]
+      ensure '2;', cursor: [0, 8]

     it "repeat with count in reverse direction", ->
-      editor.setCursorScreenPosition([0, 6])
-      keydown('f')
-      normalModeInputKeydown('c')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 8]
-      keydown('2')
-      keydown(',')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+      set cursor: [0, 6]
+      ensure ['f', normalChar: 'c'], cursor: [0, 8]
+      ensure '2,', cursor: [0, 2]

     it "shares the most recent find/till command with other editors", ->
       helpers.getEditorElement (otherEditorElement) ->
         otherEditor = otherEditorElement.getModel()

-        editor.setText("a baz bar\n")
-        editor.setCursorScreenPosition([0, 0])
+        set
+          text: "a baz bar\n"
+          cursor: [0, 0]

         otherEditor.setText("foo bar baz")
         otherEditor.setCursorScreenPosition([0, 0])

         # by default keyDown and such go in the usual editor
-        keydown('f')
-        normalModeInputKeydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+        ensure ['f', normalChar: 'b'], cursor: [0, 2]
         expect(otherEditor.getCursorScreenPosition()).toEqual [0, 0]

         # replay same find in the other editor
         keydown(';', element: otherEditorElement)
-        expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+        ensure '', cursor: [0, 2]
         expect(otherEditor.getCursorScreenPosition()).toEqual [0, 4]

         # do a till in the other editor
         keydown('t', element: otherEditorElement)
         normalModeInputKeydown('r', editor: otherEditor)
-        expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+        ensure '', cursor: [0, 2]
         expect(otherEditor.getCursorScreenPosition()).toEqual [0, 5]

         # and replay in the normal editor
-        keydown(';')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 7]
+        ensure ';',
+          cursor: [0, 7]
         expect(otherEditor.getCursorScreenPosition()).toEqual [0, 5]

   describe 'the % motion', ->
     beforeEach ->
-      editor.setText("( ( ) )--{ text in here; and a function call(with parameters) }\n")
-      editor.setCursorScreenPosition([0, 0])
+      set
+        text: "( ( ) )--{ text in here; and a function call(with parameters) }\n"
+        cursor: [0, 0]

     it 'matches the correct parenthesis', ->
-      keydown('%')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+      ensure '%', cursor: [0, 6]

     it 'matches the correct brace', ->
-      editor.setCursorScreenPosition([0, 9])
-      keydown('%')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 62]
+      set cursor: [0, 9]
+      ensure '%', cursor: [0, 62]

     it 'composes correctly with d', ->
-      editor.setCursorScreenPosition([0, 9])
-      keydown('d')
-      keydown('%')
-      expect(editor.getText()).toEqual  "( ( ) )--\n"
+      set cursor: [0, 9]
+      ensure 'd%',
+        text: "( ( ) )--\n"

     it 'moves correctly when composed with v going forward', ->
-      keydown('v')
-      keydown('h')
-      keydown('%')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 7]
+      ensure 'vh%', cursor: [0, 7]

     it 'moves correctly when composed with v going backward', ->
-      editor.setCursorScreenPosition([0, 5])
-      keydown('v')
-      keydown('%')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      set cursor: [0, 5]
+      ensure 'v%', cursor: [0, 0]

     it 'it moves appropriately to find the nearest matching action', ->
-      editor.setCursorScreenPosition([0, 3])
-      keydown('%')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-      expect(editor.getText()).toEqual  "( ( ) )--{ text in here; and a function call(with parameters) }\n"
+      set cursor: [0, 3]
+      ensure '%',
+        cursor: [0, 2]
+        text: "( ( ) )--{ text in here; and a function call(with parameters) }\n"

     it 'it moves appropriately to find the nearest matching action', ->
-      editor.setCursorScreenPosition([0, 26])
-      keydown('%')
-      expect(editor.getCursorScreenPosition()).toEqual [0, 60]
-      expect(editor.getText()).toEqual  "( ( ) )--{ text in here; and a function call(with parameters) }\n"
+      set cursor: [0, 26]
+      ensure '%',
+        cursor: [0, 60]
+        text: "( ( ) )--{ text in here; and a function call(with parameters) }\n"

     it "finds matches across multiple lines", ->
-      editor.setText("...(\n...)")
-      editor.setCursorScreenPosition([0, 0])
-      keydown("%")
-      expect(editor.getCursorScreenPosition()).toEqual([1, 3])
+      set
+        text: "...(\n...)"
+        cursor: [0, 0]
+      ensure '%',
+        cursor: [1, 3]

     it "does not affect search history", ->
-      keydown('/')
-      submitNormalModeInputText 'func'
-      expect(editor.getCursorBufferPosition()).toEqual [0, 31]
-      keydown('%')
-      expect(editor.getCursorBufferPosition()).toEqual [0, 60]
-      keydown('n')
-      expect(editor.getCursorBufferPosition()).toEqual [0, 31]
+      ensure ['/', normal: 'func'], cursor: [0, 31]
+      ensure '%', cursor: [0, 60]
+      ensure 'n', cursor: [0, 31]

   describe "scrolling screen and keeping cursor in the same screen position", ->
     beforeEach ->
@@ -1677,69 +1448,60 @@

     describe "the ctrl-u keybinding", ->
       it "moves the screen down by half screen size and keeps cursor onscreen", ->
-        keydown('u', ctrl: true)
-        expect(editor.getScrollTop()).toEqual 300
-        expect(editor.getCursorBufferPosition()).toEqual [32, 0]
+        ensure [ctrl: 'u'],
+          scrollTop: 300
+          cursor: [32, 0]

       it "selects on visual mode", ->
-        editor.setCursorBufferPosition([42, 1])
-        vimState.activateVisualMode()
-        keydown('u', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [32..42].join("\n")
+        set cursor: [42, 1]
+        ensure ['v', ctrl: 'u'],
+          selectedText: [32..42].join("\n")

       it "selects on linewise mode", ->
-        vimState.activateVisualMode('linewise')
-        keydown('u', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [32..42].join("\n").concat("\n")
+        ensure ['V', ctrl: 'u'],
+          selectedText: [32..42].join("\n").concat("\n")

     describe "the ctrl-b keybinding", ->
       it "moves screen up one page", ->
-        keydown('b', ctrl: true)
-        expect(editor.getScrollTop()).toEqual 200
-        expect(editor.getCursorScreenPosition()).toEqual [22, 0]
+        ensure [ctrl: 'b'],
+          scrollTop: 200
+          cursor: [22, 0]

       it "selects on visual mode", ->
-        editor.setCursorBufferPosition([42, 1])
-        vimState.activateVisualMode()
-        keydown('b', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [22..42].join("\n")
+        set cursor: [42, 1]
+        ensure ['v', ctrl: 'b'],
+          selectedText: [22..42].join("\n")

       it "selects on linewise mode", ->
-        vimState.activateVisualMode('linewise')
-        keydown('b', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [22..42].join("\n").concat("\n")
-
+        ensure ['V', ctrl: 'b'],
+          selectedText: [22..42].join("\n").concat("\n")

     describe "the ctrl-d keybinding", ->
       it "moves the screen down by half screen size and keeps cursor onscreen", ->
-        keydown('d', ctrl: true)
-        expect(editor.getScrollTop()).toEqual 500
-        expect(editor.getCursorBufferPosition()).toEqual [52, 0]
+        ensure [ctrl: 'd'],
+          scrollTop: 500
+          cursor: [52, 0]

       it "selects on visual mode", ->
-        editor.setCursorBufferPosition([42, 1])
-        vimState.activateVisualMode()
-        keydown('d', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [42..52].join("\n").slice(1, -1)
+        set cursor: [42, 1]
+        ensure ['v', ctrl: 'd'],
+          selectedText: [42..52].join("\n").slice(1, -1)

       it "selects on linewise mode", ->
-        vimState.activateVisualMode('linewise')
-        keydown('d', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [42..52].join("\n").concat("\n")
+        ensure ['V', ctrl: 'd'],
+          selectedText: [42..52].join("\n").concat("\n")

     describe "the ctrl-f keybinding", ->
       it "moves screen down one page", ->
-        keydown('f', ctrl: true)
-        expect(editor.getScrollTop()).toEqual 600
-        expect(editor.getCursorScreenPosition()).toEqual [62, 0]
+        ensure [ctrl: 'f'],
+          scrollTop: 600
+          cursor: [62, 0]

       it "selects on visual mode", ->
-        editor.setCursorBufferPosition([42, 1])
-        vimState.activateVisualMode()
-        keydown('f', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [42..62].join("\n").slice(1, -1)
+        set cursor: [42, 1]
+        ensure ['v', ctrl: 'f'],
+          selectedText: [42..62].join("\n").slice(1, -1)

       it "selects on linewise mode", ->
-        vimState.activateVisualMode('linewise')
-        keydown('f', ctrl: true)
-        expect(editor.getSelectedText()).toEqual [42..62].join("\n").concat("\n")
+        ensure ['V', ctrl: 'f'],
+          selectedText: [42..62].join("\n").concat("\n")


previous fix gave us three fixed specs for free

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -677,8 +677,7 @@

         it "deletes the current line plus that many previous lines", ->
           expect(editor.getText()).toBe "1\n6\n"
-          # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
-          #expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          expect(editor.getCursorScreenPosition()).toEqual [1, 0]

   describe "the + keybinding", ->
     beforeEach ->
@@ -738,8 +737,7 @@

         it "selects to the first character of the next line", ->
           expect(editor.getText()).toBe "abcdefg\n"
-          # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
-          #expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+          expect(editor.getCursorScreenPosition()).toEqual [0, 0]

     describe "with a count", ->
       beforeEach ->
@@ -762,8 +760,7 @@

         it "deletes the current line plus that many following lines", ->
           expect(editor.getText()).toBe "1\n6\n"
-          # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
-          #expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          expect(editor.getCursorScreenPosition()).toEqual [1, 0]

   describe "the _ keybinding", ->
     beforeEach ->


tidy up drawing blocks

tidy up drawing blocks

--- public/javascripts/tetris.coffee
+++ public/javascripts/tetris.coffee
@@ -51,13 +51,14 @@
       @drawShapes(c)
       @drawBounds(c)
     drawShapes: (c) ->
-      null
+
     drawBlocks: (c) ->
+      @drawBlock(c, block.x, block.y) for block in @blocks
+    drawBlock: (c, x, y) ->
       c.fillStyle = "#00b"
-      for block in @blocks
-        x = @x + (@gridSize * block.x)
-        y = @y + (@gridSize * block.y)
-        c.fillRect(x, y, @gridSize, @gridSize)
+      x = @x + (@gridSize * x)
+      y = @y + (@gridSize * y)
+      c.fillRect(x, y, @gridSize, @gridSize)
     drawBounds: (c) ->
       c.strokeStyle = "#0f0"
       start = @x + (Tetris.viewportOffset.x * @gridSize)


Slight visual change to please FireFox

Slight visual change to please FireFox

--- overview.client.coffee
+++ overview.client.coffee
@@ -94,7 +94,7 @@
 					display: 'inline-block'
 					Box: 'vertical'
 					margin: '5px 10px'
-					width: ((Page.width()-16)/3)-20 + "px"
+					width: ((Page.width()-16)/3)-30 + "px"
 				Ui.avatar Plugin.userAvatar(user),
 					size: 60
 					style:


Change profile selection behavior

Change profile selection behavior

See #3875

--- web/party/profile.coffee
+++ web/party/profile.coffee
@@ -20,7 +20,6 @@

       select: () ->
         s = @selected
-        return if selected && s != true
         @constructor.selection = {}
         if s == true
           selected = false


Added plist and recipe to XML extensions

.recipe is used by autopkg for plists

--- src/languages/xml.coffee
+++ src/languages/xml.coffee
@@ -16,7 +16,7 @@
   Supported extensions
   ###
   extensions: [
-    'sld', 'xml', 'xhtml', 'xsd', 'xsl', 'jsp', 'gsp'
+    'sld', 'xml', 'xhtml', 'xsd', 'xsl', 'jsp', 'gsp', 'plist', 'recipe'
   ]

   defaultBeautifier: "Pretty Diff"


Request: Fixed content type header parsing.

--- src/lib/ajax/ajax.coffee
+++ src/lib/ajax/ajax.coffee
@@ -43,7 +43,7 @@
       return error.call spark.ajax, error, e

     contentType = target.getResponseHeader goog.net.XhrIo.CONTENT_TYPE_HEADER
-    isJSON      = contentType.indexOf('application/json') > -1
+    isJSON      = contentType?.indexOf('application/json') > -1
     response    = if isJSON then target.getResponseJson() else target.getResponse()

     success.call spark.ajax, response, e


Adding more switch variations to the kitchen sink

--- examples/kitchen-sink/coffeescript/kitchen-sink.coffee
+++ examples/kitchen-sink/coffeescript/kitchen-sink.coffee
@@ -148,6 +148,9 @@
             xs: "6",
             label: "Time of Day",
             saved: true
+            handleWidth: 100
+            onText: "Enabled"
+            offText: "Disabled"
             errors: ["This error is an example", "As is this one"]
           f.input "time_of_night",
             type: "switch",


better evaluator factory

better evaluator factory

--- src/loader/loader.coffee
+++ src/loader/loader.coffee
@@ -287,12 +287,6 @@
             update_module_loaded_from_db: []
             evaluate_module_decoded: []

-        @_evaluators =
-            cjs: CJSEvaluator
-            amd: AMDEvaluator
-            junk: PollutionEvaluator
-            raw: RawEvaluator
-
         @version = options.version
         @prefix = options.prefix
         @hash_name = options.hash_name
@@ -307,6 +301,14 @@
         @manifest_key = @prefix + "::manifest"
         localforage.config
             name: @prefix + "-db"
+
+    _get_evaluator: (module) ->
+        return switch module.type ? "cjs"
+            when "cjs" then CJSEvaluator
+            when "amd" then AMDEvaluator
+            when "junk" then PollutionEvaluator
+            when "raw" then RawEvaluator
+            else throw new TypeError("Invalid module type `#{module.type}`")

     _prepare_url: (url) ->
         return escape(url) unless @randomize_urls
@@ -441,7 +443,8 @@
                     deps[alias] = @_all_modules[dep]
                 deps["loader"] = this

-                evaluator = new @_evaluators[module.type ? "cjs"]
+                evaluator_type = @_get_evaluator(module)
+                evaluator = new evaluator_type
                     id: module.id
                     source: module.source
                     dependencies: deps


Social: decrease limit to 10 for popular posts

--- workers/social/lib/social/cache/socialapi.coffee
+++ workers/social/lib/social/cache/socialapi.coffee
@@ -15,7 +15,7 @@
   fetchPopularPosts = (cb) ->
     opt =
       channelName : params?.section or 'Public'
-      limit       : 25
+      limit       : 10

     SocialChannel.fetchPopularPosts client, opt, cb


Add message if My Reservation is empty

Add message if My Reservation is empty

--- www/js/controller.coffee
+++ www/js/controller.coffee
@@ -5,7 +5,6 @@
 	_.extend $scope,
 		env: env
 		navigator: navigator
-

 TimeslotCtrl = ($scope, model, $location) ->
 	_.extend $scope,
@@ -170,7 +169,9 @@
 			today.setHours(0,0,0,0)
 			iDate = new Date(d)
 			iDate.setHours(0,0,0,0)
-			return today.getTime() == iDate.getTime()
+			return today.getTime() == iDate.getTime()
+		isEmpty: (obj) ->
+			return angular.equals({},obj)
 		create: ->
 			$location.url "/reservation/create"
 		delete: (obj) ->


ListView: playground update

ListView: playground update

--- playground/main.coffee
+++ playground/main.coffee
@@ -2,6 +2,8 @@
 class ListItem extends KDListItemView

   partial : ->
+
+    @setCss 'padding-left' : '50px'

     {randomIndex, id} = @getData()
     "#{id} numarali itemim ulan indexim de #{randomIndex or 'yok'}!!

"
@@ -11,21 +13,36 @@
 KDView.appendToDOMBody mainView

 listController = new KDListViewController
-  boxed : yes
   itemClass : ListItem
+  # boxed : yes
+  lastToFirst : yes

 id = 0
+mainView.addSubView input = new KDInputView
+
 mainView.addSubView new KDButtonView
   title    : 'Random indexli eleman ekle'
   callback : ->
-    if listController.itemsOrdered.length > 3
-      randomIndex = KD.utils.getRandomNumber listController.itemsOrdered.length
+    randomIndex = parseInt(input.getValue(), 10) or 0
     listController.addItem {title : Date.now(), id : ++id, randomIndex}, randomIndex
+    log listController.getListView().items.map (item) -> item.data.id
     log listController.itemsOrdered.map (item) -> item.data.id

 mainView.addSubView listController.getView()

-# And append it to DOM
+# KD.utils.defer ->

+#   for i in [0...10]
+#     if listController.itemsOrdered.length > 3
+#       randomIndex = KD.utils.getRandomNumber listController.itemsOrdered.length
+#     # randomIndex = 0
+#     log randomIndex
+#     listController.addItem {title : Date.now(), id : ++id, randomIndex}, randomIndex
+#     # log listController.itemsOrdered.map (item) -> item.data.id
+
+
+# listController.getListItems()
+
+window.kamil = listController


fix bindToBrush

fix bindToBrush

--- app/graphing.coffee
+++ app/graphing.coffee
@@ -143,10 +143,10 @@

       if params.bindToBrush == true
         params.brush ?= new Bacon.Model
-        paramModifiers.push(brushParams(params, params.brush))
+        paramModifiers.push(brushParams(params, params.brush).changes())
       else if params.bindToBrush instanceof Bacon.Observable
         params.brush ?= params.bindToBrush
-        paramModifiers.push(brushParams(params, params.bindToBrush))
+        paramModifiers.push(brushParams(params, params.bindToBrush).changes())

       if params.refreshInterval?
         paramModifiers.push(Bacon.interval(params.refreshInterval * 1000, {}).map(-> refreshTime: +new Date))


Cleaner edge IDs

Cleaner edge IDs

--- src/plugins/noflo.coffee
+++ src/plugins/noflo.coffee
@@ -230,6 +230,13 @@
       component: node.component
       metadata: node.metadata

+  edgeToId: (edge) ->
+    if edge.dataflowEdge
+      return edge.dataflowEdge.id
+    source = "#{edge.from.node} #{edge.from.port.toUpperCase()}"
+    destination = "#{edge.to.port.toUpperCase()} #{edge.to.node}"
+    "#{source} -> #{destination}"
+
   addEdge: (nfEdge, dfGraph) ->
     return unless nfEdge

@@ -239,7 +246,7 @@
       Edge = @dataflow.module 'edge'
       nfEdge.metadata = {} unless nfEdge.metadata
       dfEdge = new Edge.Model
-        id: nfEdge.from.node + ":" + nfEdge.from.port + "::" + nfEdge.to.node + ":" + nfEdge.to.port
+        id: @edgeToId nfEdge
         parentGraph: dfGraph
         source: nfEdge.from
         target: nfEdge.to


Modify holds list status line to handile single or many copies available

--- src/account/holds.coffee
+++ src/account/holds.coffee
@@ -57,9 +57,13 @@
 					'''
 				else
 					''
-			c = if o.total_holds
-					'''
-					<%= avail %> Copies available
+			c = if o.potential_copies is 1
+					'''
+					<%= avail %> copy available
+					'''
+				else if o.potential_copies > 1
+					'''
+					<%= avail %> copies available
 					'''
 				else
 					''


LineMap.clipScreenPosition relies entirely on translatePosition

--- src/atom/line-map.coffee
+++ src/atom/line-map.coffee
@@ -38,10 +38,13 @@
     @linesByDelta('bufferDelta', startRow, endRow)

   bufferLineCount: ->
-    @traverseByDelta('bufferDelta', new Point(Infinity, 0)).bufferDelta.row
+    @lineCountByDelta('bufferDelta')

   screenLineCount: ->
-    @traverseByDelta('screenDelta', new Point(Infinity, 0)).screenDelta.row
+    @lineCountByDelta('screenDelta')
+
+  lineCountByDelta: (deltaType) ->
+    @traverseByDelta(deltaType, new Point(Infinity, 0))[deltaType].row

   lastScreenRow: ->
     @screenLineCount() - 1
@@ -63,12 +66,6 @@
     new Range(start, end)

   clipScreenPosition: (screenPosition, options) ->
-    screenPosition = Point.fromObject(screenPosition)
-    maxScreenRow = @lastScreenRow()
-    if screenPosition.row > maxScreenRow
-      screenPosition.row = maxScreenRow
-      screenPosition.column = Infinity
-
     @translatePosition('screenDelta', 'screenDelta', screenPosition, options)

   spliceByDelta: (deltaType, startRow, rowCount, lineFragments) ->
@@ -114,6 +111,11 @@
       sourcePosition.row = 0
       sourcePosition.column = 0

+    maxSourceRow = @lineCountByDelta(sourceDeltaType) - 1
+    if sourcePosition.row > maxSourceRow
+      sourcePosition.row = maxSourceRow
+      sourcePosition.column = Infinity
+
     traversalResult = @traverseByDelta(sourceDeltaType, sourcePosition)
     lastLineFragment = traversalResult.lastLineFragment
     sourceDelta = traversalResult[sourceDeltaType]


fix for #8

fix for #8

--- src/tokenizer/TokenizerFactory.coffee
+++ src/tokenizer/TokenizerFactory.coffee
@@ -31,8 +31,9 @@
     return result

   makeTokenizer: (filename, supportedLanguages) ->
+    extension = ''
     matches = filename.match /\.(\w*)$/
-    extension = matches[1]?.toLowerCase()
+    extension = matches[1]?.toLowerCase() if matches

     language = TokenizerFactory::getLanguageByExtension extension


Add deprecated shim for TextEditor export

--- exports/atom.coffee
+++ exports/atom.coffee
@@ -2,6 +2,7 @@
 {Point, Range} = TextBuffer
 {File, Directory} = require 'pathwatcher'
 {Emitter, Disposable, CompositeDisposable} = require 'event-kit'
+Grim = require 'grim'

 module.exports =
   BufferedNodeProcess: require '../src/buffered-node-process'
@@ -21,4 +22,20 @@
 # only be exported when not running as a child node process
 unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
   module.exports.Task = require '../src/task'
-  module.exports.TextEditor = require '../src/text-editor'
+
+  TextEditor = (params) ->
+    atom.workspace.buildTextEditor(params)
+
+  TextEditor.prototype = require('../src/text-editor').prototype
+
+  Object.defineProperty module.exports, 'TextEditor',
+    enumerable: true
+    get: ->
+      Grim.deprecate """
+        The `TextEditor` constructor is no longer public.
+
+        To construct a text editor, use `atom.workspace.buildTextEditor()`.
+        To check if an object is a text editor, look for for the existence of
+        a public method that you're using (e.g. `::getText`).
+      """
+      TextEditor


fix menu capitalization for 'Color Scheme'

--- src/ui/views/menu.coffee
+++ src/ui/views/menu.coffee
@@ -52,7 +52,7 @@
             enabled: viewstate.loggedin
             click: (it) -> action 'showconvlast', it.checked
         }, {
-            label: 'Color scheme'
+            label: 'Color Scheme'
             submenu: [
                 {
                     label: 'Default'