diff --git a/lib/editor-decorator.coffee b/lib/editor-decorator.coffee new file mode 100644 index 0000000..e2d242f --- /dev/null +++ b/lib/editor-decorator.coffee @@ -0,0 +1,20 @@ +# Decorate any lines within an {Editor} that correspond to an active {Stacktrace}. + +{Stacktrace} = require './stacktrace' + +markers = [] + +module.exports = (editor) -> + m.destroy() for m in markers + markers = [] + + active = Stacktrace.getActivated() + return unless active? + + for frame in active.frames + if frame.realPath is editor.getPath() + range = editor.getBuffer().rangeForRow frame.bufferLineNumber() + marker = editor.markBufferRange range + editor.decorateMarker marker, type: 'line', class: 'line-stackframe' + editor.decorateMarker marker, type: 'gutter', class: 'gutter-stackframe' + markers.push marker diff --git a/lib/main.coffee b/lib/main.coffee index cf64fba..f24b80c 100644 --- a/lib/main.coffee +++ b/lib/main.coffee @@ -1,6 +1,7 @@ EnterDialog = require './enter-dialog' {Stacktrace} = require './stacktrace' {StacktraceView} = require './stacktrace-view' +editorDecorator = require './editor-decorator' module.exports = @@ -13,6 +14,10 @@ module.exports = text = (s.getText() for s in (selections or [])).join '' atom.emit 'stacktrace:accept-trace', trace: text + atom.workspace.eachEditor editorDecorator + Stacktrace.on 'active-changed', -> + editorDecorator(e) for e in atom.workspace.getEditors() + StacktraceView.registerIn(atom.workspace) atom.on 'stacktrace:accept-trace', ({trace}) => @@ -21,6 +26,7 @@ module.exports = atom.workspace.open trace.getUrl() deactivate: -> + Stacktrace.off 'active-changed' atom.off 'stacktrace:accept-trace' serialize: -> diff --git a/lib/stacktrace.coffee b/lib/stacktrace.coffee index 413f38e..14aaf8e 100644 --- a/lib/stacktrace.coffee +++ b/lib/stacktrace.coffee @@ -92,6 +92,10 @@ class Frame constructor: (@rawLine, @rawPath, @lineNumber, @functionName) -> @realPath = @rawPath + # Public: Return the zero-indexed line number. + # + bufferLineNumber: -> @lineNumber - 1 + # Public: Asynchronously collect n lines of context around the specified line number in this # frame's source file. # diff --git a/spec/editor-marker-spec.coffee b/spec/editor-marker-spec.coffee new file mode 100644 index 0000000..425a769 --- /dev/null +++ b/spec/editor-marker-spec.coffee @@ -0,0 +1,64 @@ +path = require 'path' +{Editor, WorkspaceView} = require 'atom' + +{Stacktrace, Frame} = require '../lib/stacktrace' +editorDecorator = require '../lib/editor-decorator' + +framePath = (fname) -> path.join __dirname, 'fixtures', fname + +frames = [ + new Frame('raw0', framePath('bottom.rb'), 12, 'botfunc') + new Frame('raw1', framePath('middle.rb'), 42, 'midfunc') + new Frame('raw2', framePath('top.rb'), 37, 'topfunc') + new Frame('raw3', framePath('middle.rb'), 5, 'otherfunc') +] +trace = new Stacktrace(frames, 'Boom') + +describe 'editorDecorator', -> + [editor, editorView] = [] + + beforeEach -> + atom.workspaceView = new WorkspaceView + + afterEach -> + Stacktrace.getActivated()?.deactivate() + + withEditorOn = (fname, callback) -> + waitsForPromise -> + atom.workspace.open(framePath fname) + + runs -> + atom.workspaceView.attachToDom() + editorView = atom.workspaceView.getActiveView() + editor = editorView.getEditor() + callback() + + it 'does nothing if there is no active trace', -> + expect(Stacktrace.getActivated()).toBeNull() + + withEditorOn 'bottom.rb', -> + editorDecorator(editor) + expect(editorView.find '.line.line-stackframe').toHaveLength 0 + + describe 'with an active trace', -> + + beforeEach -> trace.activate() + + it "does nothing if the file doesn't appear in the active trace", -> + withEditorOn 'context.txt', -> + editorDecorator(editor) + expect(editorView.find '.line.line-stackframe').toHaveLength 0 + + it 'decorates stackframe lines in applicable editors', -> + withEditorOn 'bottom.rb', -> + editorDecorator(editor) + decorated = editorView.find '.line.line-stackframe' + expect(decorated).toHaveLength 1 + expect(decorated.text()).toEqual(" puts 'this is the stack line'") + + it 'removes prior decorations when deactivated', -> + withEditorOn 'bottom.rb', -> + editorDecorator(editor) + trace.deactivate() + editorDecorator(editor) + expect(editorView.find '.line.line-stackframe').toHaveLength 0 diff --git a/spec/fixtures/bottom.rb b/spec/fixtures/bottom.rb new file mode 100644 index 0000000..fb32573 --- /dev/null +++ b/spec/fixtures/bottom.rb @@ -0,0 +1,14 @@ +# This isn't a real Ruby file. It's a test fixture I can reference in other places. + + + + + + + + +def botfunc + before = true + puts 'this is the stack line' + after = false +end diff --git a/spec/fixtures/middle.rb b/spec/fixtures/middle.rb new file mode 100644 index 0000000..d8d7ee3 --- /dev/null +++ b/spec/fixtures/middle.rb @@ -0,0 +1,43 @@ +# This isn't a real Ruby file. It's a test fixture I can reference in other places. +# This one has two lines in the "stack trace". + +def otherfunc + puts 'this is the line' + # and more stuff +end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +def botfunc + # more things + puts 'this is the line' +end diff --git a/spec/fixtures/top.rb b/spec/fixtures/top.rb new file mode 100644 index 0000000..d0c6839 --- /dev/null +++ b/spec/fixtures/top.rb @@ -0,0 +1,38 @@ +# This isn't a real Ruby file. It's a test fixture I can reference in other places. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +def topfunc + # things + puts 'this is the line' +end diff --git a/stylesheets/stacktrace.less b/stylesheets/stacktrace.less index 282fe3c..5bfc3c8 100644 --- a/stylesheets/stacktrace.less +++ b/stylesheets/stacktrace.less @@ -3,6 +3,10 @@ // See https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less // for a full listing of what's available. @import "ui-variables"; +@import "syntax-variables"; + +@stackframe-background: mix(@background-color-info, @syntax-background-color, 40%); +@stackframe-gutter-background: mix(@background-color-info, @syntax-gutter-background-color, 40%); .stacktrace { &.enter-dialog .editor { @@ -45,3 +49,13 @@ } } + +.editor { + .line.line-stackframe { + background: @stackframe-background; + } + + .gutter .gutter-stackframe { + background: @stackframe-gutter-background; + } +}