diff --git a/.atom/config.json b/.atom/config.json new file mode 100644 index 000000000..f6b59770b --- /dev/null +++ b/.atom/config.json @@ -0,0 +1,11 @@ +{ + "editor": { + "fontSize": 16 + }, + "core": { + "themes": [ + "Atom - Dark", + "IR_Black" + ] + } +} diff --git a/.atom/packages/Readme.md b/.atom/packages/Readme.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/.atom/themes/README.md b/.atom/themes/README.md new file mode 100644 index 000000000..dbedd5e13 --- /dev/null +++ b/.atom/themes/README.md @@ -0,0 +1 @@ +All themes in this directory will be automatically loaded diff --git a/.atom/user.css b/.atom/user.css index f53057581..d63ad257e 100644 --- a/.atom/user.css +++ b/.atom/user.css @@ -1,8 +1,8 @@ -// User styles +/* User styles */ .tree-view { } .editor { -} \ No newline at end of file +} diff --git a/src/packages/editor-stats/index.coffee b/src/packages/editor-stats/index.coffee new file mode 100644 index 000000000..e743c0f18 --- /dev/null +++ b/src/packages/editor-stats/index.coffee @@ -0,0 +1,16 @@ +DeferredAtomPackage = require 'deferred-atom-package' +Stats = require './src/stats' + +module.exports = +class EditorStats extends DeferredAtomPackage + loadEvents: ['editor-stats:toggle'] + instanceClass: 'editor-stats/src/editor-stats-view' + stats: new Stats + + activate: (rootView) -> + super + + rootView.on 'keydown', => @stats.track() + rootView.on 'mouseup', => @stats.track() + + onLoadEvent: (event, instance) -> instance.toggle(@stats) diff --git a/src/packages/editor-stats/keymaps/editor-stats.cson b/src/packages/editor-stats/keymaps/editor-stats.cson new file mode 100644 index 000000000..819b7c04f --- /dev/null +++ b/src/packages/editor-stats/keymaps/editor-stats.cson @@ -0,0 +1,2 @@ +'body': + 'meta-alt-s': 'editor-stats:toggle' diff --git a/src/packages/editor-stats/spec/editor-stats-spec.coffee b/src/packages/editor-stats/spec/editor-stats-spec.coffee new file mode 100644 index 000000000..ca274a252 --- /dev/null +++ b/src/packages/editor-stats/spec/editor-stats-spec.coffee @@ -0,0 +1,46 @@ +$ = require 'jquery' +RootView = require 'root-view' +EditorStats = require 'editor-stats/src/editor-stats-view' + +describe "EditorStats", -> + [rootView, editorStats, time] = [] + + simulateKeyUp = (key) -> + e = $.Event "keydown", keyCode: key.charCodeAt(0) + rootView.trigger(e) + + simulateClick = -> + e = $.Event "mouseup" + rootView.trigger(e) + + beforeEach -> + rootView = new RootView(require.resolve('fixtures/sample.js')) + + date = new Date() + mins = date.getMinutes() + hours = date.getHours() + + mins = if mins == 60 then '01' else mins + 1 + time = "#{hours}:#{mins}" + + editorStatsPackage = atom.loadPackage('editor-stats') + editorStatsPackage.getInstance() + editorStats = editorStatsPackage.stats + editorStats.clear() + + afterEach -> + rootView.deactivate() + + describe "when a keyup event is triggered", -> + it "records the number of times a keyup is triggered", -> + simulateKeyUp('a') + expect(editorStats.eventLog[time]).toBe 1 + simulateKeyUp('b') + expect(editorStats.eventLog[time]).toBe 2 + + describe "when a mouseup event is triggered", -> + it "records the number of times a mouseup is triggered", -> + simulateClick() + expect(editorStats.eventLog[time]).toBe 1 + simulateClick() + expect(editorStats.eventLog[time]).toBe 2 diff --git a/src/packages/editor-stats/src/editor-stats-view.coffee b/src/packages/editor-stats/src/editor-stats-view.coffee new file mode 100644 index 000000000..bd93cc1c3 --- /dev/null +++ b/src/packages/editor-stats/src/editor-stats-view.coffee @@ -0,0 +1,100 @@ +ScrollView = require 'scroll-view' +d3 = require 'd3.v3' +_ = require 'underscore' +$ = require 'jquery' + +module.exports = +class EditorStatsView extends ScrollView + @activate: (rootView, state) -> + @instance = new EditorStatsView(rootView) + + @content: (rootView) -> + @div class: 'editor-stats-wrapper', tabindex: -1, => + @div class: 'editor-stats', outlet: 'editorStats' + + pt: 15 + pl: 10 + pb: 3 + pr: 25 + + initialize: (@rootView) -> + super + + resizer = => + @draw() + @update() + @subscribe $(window), 'resize', _.debounce(resizer, 300) + + draw: -> + @editorStats.empty() + @x ?= d3.scale.ordinal().domain d3.range(@stats.hours * 60) + @y ?= d3.scale.linear() + w = @rootView.vertical.width() + h = @height() + data = d3.entries @stats.eventLog + max = d3.max data, (d) -> d.value + + @x.rangeBands [0, w - @pl - @pr], 0.2 + @y.domain([0, max]).range [h - @pt - @pb, 0] + + @xaxis ?= d3.svg.axis().scale(@x).orient('top') + .tickSize(-h + @pt + @pb) + .tickFormat (d) => + d = new Date(@stats.startDate.getTime() + (d * 6e4)) + mins = d.getMinutes() + mins = "0#{mins}" if mins <= 9 + "#{d.getHours()}:#{mins}" + + vis = d3.select(@editorStats.get(0)).append('svg') + .attr('width', w) + .attr('height', h) + .append('g') + .attr('transform', "translate(#{@pl},#{@pt})") + + vis.append('g') + .attr('class', 'x axis') + .call(@xaxis) + .selectAll('g') + .classed('minor', (d, i) -> i % 5 == 0 && i % 15 != 0) + .style 'display', (d, i) -> + if i % 15 == 0 || i % 5 == 0 || i == data.length - 1 + 'block' + else + 'none' + + @bars = vis.selectAll('rect.bar') + .data(data) + .enter().append('rect') + .attr('x', (d, i) => @x i) + .attr('height', (d, i) => h - @y(d.value) - @pt - @pb) + .attr('y', (d) => @y(d.value)) + .attr('width', @x.rangeBand()) + .attr('class', 'bar') + + setTimeout((=> @update()), 100) + @updateInterval = setInterval((=> @update()), 5000) + + update: -> + newData = d3.entries @stats.eventLog + max = d3.max newData, (d) -> d.value + @y.domain [0, max] + h = @height() + @bars.data(newData).transition() + .attr('height', (d, i) => h - @y(d.value) - @pt - @pb) + .attr('y', (d, i) => @y(d.value)) + @bars.classed('max', (d, i) -> d.value == max) + + toggle: (@stats) -> + if @hasParent() + @detach() + else + @attach() + + attach: -> + @rootView.vertical.append(@) + @draw() + + detach: -> + super() + clearInterval(@updateInterval) + @rootView.focus() diff --git a/src/packages/editor-stats/src/stats.coffee b/src/packages/editor-stats/src/stats.coffee new file mode 100644 index 000000000..5e9c6700d --- /dev/null +++ b/src/packages/editor-stats/src/stats.coffee @@ -0,0 +1,29 @@ +module.exports = +class Stats + startDate: new Date + hours: 6 + eventLog: [] + + constructor: -> + date = new Date(@startDate) + future = new Date(date.getTime() + (36e5 * @hours)) + @eventLog[@time(date)] = 0 + + while date < future + @eventLog[@time(date)] = 0 + + clear: -> + @eventLog = [] + + track: -> + date = new Date + times = @time date + @eventLog[times] ?= 0 + @eventLog[times] += 1 + @eventLog.shift() if @eventLog.length > (@hours * 60) + + time: (date) -> + date.setTime(date.getTime() + 6e4) + hour = date.getHours() + minute = date.getMinutes() + "#{hour}:#{minute}" diff --git a/src/packages/editor-stats/stylesheets/editor-stats.css b/src/packages/editor-stats/stylesheets/editor-stats.css new file mode 100644 index 000000000..a7d5e3ff2 --- /dev/null +++ b/src/packages/editor-stats/stylesheets/editor-stats.css @@ -0,0 +1,45 @@ +.editor-stats-wrapper { + padding: 5px; + box-sizing: border-box; + border-top: 1px solid rgba(255, 255, 255, 0.05); + z-index: 9999; +} + +.editor-stats { + height: 50px; + width: 100%; + background: #1d1f21; + border: 1px solid rgba(0, 0, 0, 0.3); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + border-right: 1px solid rgba(255, 255, 255, 0.1); +} + +.editor-stats rect.bar { + fill: rgba(255, 255, 255, 0.2); + shape-rendering: crispedges; +} + +.editor-stats rect.bar.max { + fill: rgba(0, 163, 255, 1); +} + +.editor-stats text { + font-size: 10px; + fill: rgba(255, 255, 255, 0.2); + font-family: Courier; +} + +.editor-stats .minor text { + display: none; +} + +.editor-stats line { + stroke: #ccc; + stroke-opacity: 0.05; + stroke-width: 1px; + shape-rendering: crispedges; +} + +.editor-stats path.domain { + fill: none; +} diff --git a/src/packages/tree-view/spec/tree-view-spec.coffee b/src/packages/tree-view/spec/tree-view-spec.coffee index f0a83fe63..ab6d16d1a 100644 --- a/src/packages/tree-view/spec/tree-view-spec.coffee +++ b/src/packages/tree-view/spec/tree-view-spec.coffee @@ -761,7 +761,7 @@ describe "TreeView", -> expect(addDialog.miniEditor.getText().length).toBe 0 - fdescribe "tree-view:move", -> + describe "tree-view:move", -> describe "when a file is selected", -> moveDialog = null