mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Pull out command-logger package to separate repo
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
"yaml-tmbundle": "1.0.0",
|
||||
"archive-view": "0.1.0",
|
||||
"autoflow": "0.1.0",
|
||||
"command-logger": "0.1.0",
|
||||
"spell-check": "0.1.0",
|
||||
"terminal": "0.3.0"
|
||||
},
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
{$$$} = require 'space-pen'
|
||||
ScrollView = require 'scroll-view'
|
||||
_ = require 'underscore'
|
||||
humanize = require 'humanize-plus'
|
||||
|
||||
module.exports =
|
||||
class CommandLoggerView extends ScrollView
|
||||
@content: (rootView) ->
|
||||
@div class: 'command-logger', tabindex: -1, =>
|
||||
@h4 class: 'category-header', outlet: 'categoryHeader'
|
||||
@h5 class: 'category-summary', outlet: 'categorySummary'
|
||||
@div class: 'tree-map', outlet: 'treeMap'
|
||||
|
||||
eventLog: null
|
||||
ignoredEvents: [
|
||||
'core:backspace'
|
||||
'core:cancel'
|
||||
'core:confirm'
|
||||
'core:delete'
|
||||
'core:move-down'
|
||||
'core:move-left'
|
||||
'core:move-right'
|
||||
'core:move-up'
|
||||
'editor:newline'
|
||||
'tree-view:directory-modified'
|
||||
]
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
|
||||
@command 'core:cancel', => @detach()
|
||||
@on 'blur', => @detach() unless document.activeElement is this[0]
|
||||
|
||||
toggle: (@eventLog={}) ->
|
||||
if @hasParent()
|
||||
@detach()
|
||||
else
|
||||
@attach()
|
||||
|
||||
createNodes: ->
|
||||
categories = {}
|
||||
for eventName, details of @eventLog
|
||||
continue if _.contains(@ignoredEvents, eventName)
|
||||
categoryStart = eventName.indexOf(':')
|
||||
if categoryStart is -1
|
||||
categoryName = 'Uncategorized'
|
||||
else
|
||||
categoryName = _.humanizeEventName(eventName.substring(0, categoryStart))
|
||||
category = categories[categoryName]
|
||||
unless category
|
||||
category =
|
||||
name: _.humanizeEventName(categoryName)
|
||||
children: []
|
||||
categories[categoryName] = category
|
||||
category.children.push
|
||||
name: "#{_.humanizeEventName(eventName.substring(categoryStart + 1))} #{details.count}"
|
||||
size: details.count
|
||||
_.toArray(categories)
|
||||
|
||||
createNodeContent: (node) ->
|
||||
$$$ ->
|
||||
@div style: "height:#{node.dy - 1}px;width:#{node.dx - 1}px", =>
|
||||
@span node.name
|
||||
|
||||
updateCategoryHeader: (node) ->
|
||||
@categoryHeader.text("#{node.name} Commands")
|
||||
reduceRunCount = (previous, current) ->
|
||||
if current.size?
|
||||
previous + current.size
|
||||
else if current.children?.length > 0
|
||||
current.children.reduce(reduceRunCount, previous)
|
||||
else
|
||||
previous
|
||||
runCount = node.children.reduce(reduceRunCount, 0)
|
||||
reduceCommandCount = (previous, current) ->
|
||||
if current.children?.length > 0
|
||||
current.children.reduce(reduceCommandCount, previous)
|
||||
else
|
||||
previous + 1
|
||||
commandCount = node.children.reduce(reduceCommandCount, 0)
|
||||
|
||||
commandText = "#{humanize.intcomma(commandCount)} #{humanize.pluralize(commandCount, 'command')}"
|
||||
invocationText = "#{humanize.intcomma(runCount)} #{humanize.pluralize(runCount, 'invocation')}"
|
||||
@categorySummary.text("#{commandText}, #{invocationText}")
|
||||
|
||||
updateTreeMapSize: ->
|
||||
@treeMap.width(@width() - 20)
|
||||
@treeMap.height(@height() - @categoryHeader.outerHeight() - @categorySummary.outerHeight() - 20)
|
||||
|
||||
addTreeMap: ->
|
||||
root =
|
||||
name: 'All'
|
||||
children: @createNodes()
|
||||
node = root
|
||||
|
||||
@treeMap.empty()
|
||||
|
||||
@updateCategoryHeader(root)
|
||||
@updateTreeMapSize()
|
||||
w = @treeMap.width()
|
||||
h = @treeMap.height()
|
||||
|
||||
d3 = require 'd3'
|
||||
|
||||
x = d3.scale.linear().range([0, w])
|
||||
y = d3.scale.linear().range([0, h])
|
||||
color = d3.scale.category20()
|
||||
|
||||
zoom = (d) =>
|
||||
@updateCategoryHeader(d)
|
||||
kx = w / d.dx
|
||||
ky = h / d.dy
|
||||
x.domain([d.x, d.x + d.dx])
|
||||
y.domain([d.y, d.y + d.dy])
|
||||
|
||||
t = svg.selectAll('g.node')
|
||||
.transition()
|
||||
.duration(750)
|
||||
.attr('transform', (d) -> "translate(#{x(d.x)},#{y(d.y)})")
|
||||
|
||||
t.select('rect')
|
||||
.attr('width', (d) -> kx * d.dx - 1)
|
||||
.attr('height', (d) -> ky * d.dy - 1)
|
||||
|
||||
t.select('.foreign-object')
|
||||
.attr('width', (d) -> kx * d.dx - 1)
|
||||
.attr('height', (d) -> ky * d.dy - 1)
|
||||
|
||||
t.select('.command-logger-node-text div')
|
||||
.attr('style', (d) -> "height:#{ky * d.dy - 1}px;width:#{kx * d.dx - 1}px")
|
||||
|
||||
node = d
|
||||
d3.event.stopPropagation()
|
||||
|
||||
treemap = d3.layout.treemap()
|
||||
.round(false)
|
||||
.size([w, h])
|
||||
.sticky(true)
|
||||
.value((d) -> d.size)
|
||||
|
||||
svg = d3.select('.command-logger .tree-map')
|
||||
.append('div')
|
||||
.style('width', "#{w}px")
|
||||
.style('height', "#{h}px")
|
||||
.append('svg')
|
||||
.attr('width', w)
|
||||
.attr('height', h)
|
||||
.append('g')
|
||||
.attr('transform', 'translate(.5,.5)')
|
||||
|
||||
nodes = treemap.nodes(root).filter((d) -> not d.children)
|
||||
|
||||
cell = svg.selectAll('g')
|
||||
.data(nodes)
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', 'node')
|
||||
.attr('transform', (d) -> "translate(#{d.x},#{d.y})")
|
||||
.on('click', (d) -> if node is d.parent then zoom(root) else zoom(d.parent))
|
||||
|
||||
cell.append('rect')
|
||||
.attr('width', (d) -> d.dx - 1)
|
||||
.attr('height', (d) -> d.dy - 1)
|
||||
.style('fill', (d) -> color(d.parent.name))
|
||||
|
||||
cell.append('foreignObject')
|
||||
.attr('width', (d) -> d.dx - 1)
|
||||
.attr('height', (d) -> d.dy - 1)
|
||||
.attr('class', 'foreign-object')
|
||||
.append('xhtml:body')
|
||||
.attr('class', 'command-logger-node-text')
|
||||
.html((d) => @createNodeContent(d))
|
||||
|
||||
d3.select('.command-logger').on('click', -> zoom(root))
|
||||
|
||||
attach: ->
|
||||
rootView.append(this)
|
||||
@addTreeMap()
|
||||
@focus()
|
||||
|
||||
detach: ->
|
||||
return if @detaching
|
||||
@detaching = true
|
||||
super
|
||||
rootView.focus()
|
||||
@detaching = false
|
||||
@@ -1,41 +0,0 @@
|
||||
$ = require 'jquery'
|
||||
|
||||
module.exports =
|
||||
eventLog: {}
|
||||
commandLoggerView: null
|
||||
originalTrigger: null
|
||||
|
||||
activate: (state) ->
|
||||
@eventLog = state.eventLog ? {}
|
||||
rootView.command 'command-logger:clear-data', => @eventLog = {}
|
||||
rootView.command 'command-logger:toggle', => @createView().toggle(@eventLog)
|
||||
|
||||
registerTriggeredEvent = (eventName) =>
|
||||
eventNameLog = @eventLog[eventName]
|
||||
unless eventNameLog
|
||||
eventNameLog =
|
||||
count: 0
|
||||
name: eventName
|
||||
@eventLog[eventName] = eventNameLog
|
||||
eventNameLog.count++
|
||||
eventNameLog.lastRun = new Date().getTime()
|
||||
trigger = $.fn.trigger
|
||||
@originalTrigger = trigger
|
||||
$.fn.trigger = (event) ->
|
||||
eventName = event.type ? event
|
||||
registerTriggeredEvent(eventName) if $(this).events()[eventName]
|
||||
trigger.apply(this, arguments)
|
||||
|
||||
deactivate: ->
|
||||
$.fn.trigger = @originalTrigger if @originalTrigger?
|
||||
@commandLoggerView = null
|
||||
@eventLog = {}
|
||||
|
||||
serialize: ->
|
||||
{@eventLog}
|
||||
|
||||
createView: ->
|
||||
unless @commandLoggerView?
|
||||
CommandLoggerView = require './command-logger-view'
|
||||
@commandLoggerView = new CommandLoggerView
|
||||
@commandLoggerView
|
||||
@@ -1,2 +0,0 @@
|
||||
'main': './lib/command-logger'
|
||||
'description': 'View a heat map of your Atom activity. Open from the command palette.'
|
||||
@@ -1,53 +0,0 @@
|
||||
RootView = require 'root-view'
|
||||
CommandLogger = require 'command-logger/lib/command-logger-view'
|
||||
|
||||
describe "CommandLogger", ->
|
||||
[commandLogger, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
window.rootView = new RootView
|
||||
rootView.open('sample.js')
|
||||
commandLogger = atom.activatePackage('command-logger').mainModule
|
||||
commandLogger.eventLog = {}
|
||||
editor = rootView.getActiveView()
|
||||
|
||||
describe "when a command is triggered", ->
|
||||
it "records the number of times the command is triggered", ->
|
||||
expect(commandLogger.eventLog['core:backspace']).toBeUndefined()
|
||||
editor.trigger 'core:backspace'
|
||||
expect(commandLogger.eventLog['core:backspace'].count).toBe 1
|
||||
editor.trigger 'core:backspace'
|
||||
expect(commandLogger.eventLog['core:backspace'].count).toBe 2
|
||||
|
||||
it "records the date the command was last triggered", ->
|
||||
expect(commandLogger.eventLog['core:backspace']).toBeUndefined()
|
||||
editor.trigger 'core:backspace'
|
||||
lastRun = commandLogger.eventLog['core:backspace'].lastRun
|
||||
expect(lastRun).toBeGreaterThan 0
|
||||
start = new Date().getTime()
|
||||
waitsFor ->
|
||||
new Date().getTime() > start
|
||||
|
||||
runs ->
|
||||
editor.trigger 'core:backspace'
|
||||
expect(commandLogger.eventLog['core:backspace'].lastRun).toBeGreaterThan lastRun
|
||||
|
||||
describe "when the data is cleared", ->
|
||||
it "removes all triggered events from the log", ->
|
||||
expect(commandLogger.eventLog['core:backspace']).toBeUndefined()
|
||||
editor.trigger 'core:backspace'
|
||||
expect(commandLogger.eventLog['core:backspace'].count).toBe 1
|
||||
rootView.trigger 'command-logger:clear-data'
|
||||
expect(commandLogger.eventLog['core:backspace']).toBeUndefined()
|
||||
|
||||
describe "when an event is ignored", ->
|
||||
it "does not create a node for that event", ->
|
||||
commandLoggerView = commandLogger.createView()
|
||||
commandLoggerView.ignoredEvents.push 'editor:delete-line'
|
||||
editor.trigger 'editor:delete-line'
|
||||
commandLoggerView.eventLog = commandLogger.eventLog
|
||||
nodes = commandLoggerView.createNodes()
|
||||
for node in nodes
|
||||
continue unless node.name is 'Editor'
|
||||
for child in node.children
|
||||
expect(child.name.indexOf('Delete Line')).toBe -1
|
||||
@@ -1,20 +0,0 @@
|
||||
.command-logger {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.command-logger-node-text div {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.command-logger-node-text span {
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
Reference in New Issue
Block a user