Jump to error when clicking on log entry

This commit is contained in:
James Allen 2014-06-30 13:41:32 +01:00
parent 8b6f962275
commit 797dcf5c84
13 changed files with 330 additions and 37 deletions

View file

@ -16,12 +16,14 @@ div.full-size(
font-size="settings.fontSize",
auto-complete="settings.autoComplete",
spell-check-language="project.spellCheckLanguage",
annotations="onlineUserCursorAnnotations[editor.open_doc_id]"
highlights="onlineUserCursorHighlights[editor.open_doc_id]"
show-print-margin="false",
sharejs-doc="editor.sharejs_doc",
last-updated="editor.last_updated",
cursor-position="editor.cursorPosition",
resize-on="layout:main:resize,layout:pdf:resize"
goto-line="editor.gotoLine",
resize-on="layout:main:resize,layout:pdf:resize",
annotations="pdf.logEntryAnnotations[editor.open_doc_id]"
)
.ui-layout-east

View file

@ -59,13 +59,14 @@ div.full-size(ng-controller="PdfController")
strong Compile Error.
span Sorry, your LaTeX code couldn't compile for some reason. Please check the errors below for details, or view the raw log.
div(ng-repeat="entry in pdf.logEntries.all")
div(ng-repeat="entry in pdf.logEntries.all", ng-controller="PdfLogEntryController")
.alert(
ng-class="{\
'alert-danger': entry.level == 'error',\
'alert-warning': entry.level == 'warning',\
'alert-info': entry.level == 'typesetting'\
}"
ng-click="openInEditor(entry)"
)
span.line-no
span(ng-show="entry.file") {{ entry.file }}

View file

@ -71,7 +71,7 @@ div#trackChanges(ng-show="ui.view == 'track-changes'")
theme="settings.theme",
font-size="settings.fontSize",
text="trackChanges.diff.text",
annotations="trackChanges.diff.annotations",
highlights="trackChanges.diff.highlights",
read-only="true",
resize-on="layout:main:resize"
)

View file

@ -10,6 +10,7 @@ define [
open_doc_id: null
opening: true
cursorPosition: null
gotoLine: null
}
@$scope.$on "entity:selected", (event, entity) =>
@ -33,18 +34,23 @@ define [
openDoc: (doc, options = {}) ->
@$scope.ui.view = "editor"
done = () =>
if options.gotoLine?
@$scope.editor.gotoLine = options.gotoLine
console.log "Trying to open doc", doc.id
return if doc.id == @$scope.editor.open_doc_id and !options.forceReopen
if doc.id == @$scope.editor.open_doc_id and !options.forceReopen
@$scope.$apply () =>
done()
return
@$scope.editor.open_doc_id = doc.id
console.log "Actually opening doc", doc.id
$.localStorage "doc.open_id.#{@$scope.project_id}", doc.id
@ide.fileTreeManager.selectEntity(doc)
@$scope.editor.opening = true
@_openNewDocument doc, (error, sharejs_doc) =>
console.log "OPENED DOC", error, sharejs_doc
if error?
@ide.showGenericServerErrorMessage()
return
@ -54,6 +60,7 @@ define [
@$scope.$apply () =>
@$scope.editor.opening = false
@$scope.editor.sharejs_doc = sharejs_doc
done()
_openNewDocument: (doc, callback = (error, sharejs_doc) ->) ->
current_sharejs_doc = @$scope.editor.sharejs_doc

View file

@ -11,6 +11,13 @@ define [], () ->
@gotoStoredPosition()
@$scope.$watch "gotoLine", (value) =>
console.log "Going to line", value
if value?
setTimeout () =>
@gotoLine(value)
, 0
onScrollTopChange: (event) ->
if !@ignoreCursorPositionChanges and doc_id = @$scope.sharejsDoc?.doc_id
docPosition = $.localStorage("doc.position.#{doc_id}") || {}
@ -30,4 +37,7 @@ define [], () ->
@ignoreCursorPositionChanges = true
@editor.moveCursorToPosition(pos.cursorPosition or {row: 0, column: 0})
@editor.getSession().setScrollTop(pos.scrollTop or 0)
delete @ignoreCursorPositionChanges
delete @ignoreCursorPositionChanges
gotoLine: (line) ->
@editor.moveCursorToPosition({row: line, column: 0})

View file

@ -4,7 +4,7 @@ define [
"ide/editor/undo/UndoManager"
"ide/editor/auto-complete/AutoCompleteManager"
"ide/editor/spell-check/SpellCheckManager"
"ide/editor/annotations/AnnotationsManager"
"ide/editor/highlights/HighlightsManager"
"ide/editor/cursor-position/CursorPositionManager"
"ace/keyboard/vim"
"ace/keyboard/emacs"
@ -26,9 +26,11 @@ define [
lastUpdated: "="
spellCheckLanguage: "="
cursorPosition: "="
annotations: "="
highlights: "="
text: "="
readOnly: "="
gotoLine: "="
annotations: "="
}
link: (scope, element, attrs) ->
# Don't freak out if we're already in an apply callback
@ -100,15 +102,26 @@ define [
session.setUseWrapMode(true)
session.setMode(new LatexMode())
scope.$watch "annotations", (annotations) ->
console.log "SETTING ANNOTATIONS", annotations
if annotations?
session = editor.getSession()
session.setAnnotations annotations
scope.$watch "readOnly", (value) ->
editor.setReadOnly !!value
resetSession = () ->
session = editor.getSession()
session.setUseWrapMode(true)
session.setMode(new LatexMode())
session.setAnnotations scope.annotations
attachToAce = (sharejs_doc) ->
lines = sharejs_doc.getSnapshot().split("\n")
editor.setSession(new EditSession(lines))
resetSession()
session = editor.getSession()
session.setUseWrapMode(true)
session.setMode(new LatexMode())
autoCompleteManager.bindToSession(session)
annotationsManager.redrawAnnotations()

View file

@ -0,0 +1,224 @@
define [
"ace/range"
], () ->
Range = require("ace/range").Range
class HighlightsManager
constructor: (@$scope, @editor, @element) ->
@markerIds = []
@labels = []
@$scope.annotationLabel = {
show: false
right: "auto"
left: "auto"
top: "auto"
bottom: "auto"
backgroundColor: "black"
text: ""
}
@$scope.$watch "highlights", (value) =>
@redrawAnnotations()
@$scope.$watch "theme", (value) =>
@redrawAnnotations()
@editor.on "mousemove", (e) =>
position = @editor.renderer.screenToTextCoordinates(e.clientX, e.clientY)
e.position = position
@showAnnotationLabels(position)
redrawAnnotations: () ->
@_clearMarkers()
@_clearLabels()
for annotation in @$scope.highlights or []
do (annotation) =>
colorScheme = @_getColorScheme(annotation.hue)
if annotation.cursor?
@labels.push {
text: annotation.text
range: new Range(
annotation.cursor.row, annotation.cursor.column,
annotation.cursor.row, annotation.cursor.column + 1
)
colorScheme: colorScheme
snapToStartOfRange: true
}
@_drawCursor(annotation, colorScheme)
else if annotation.highlight?
@labels.push {
text: annotation.label
range: new Range(
annotation.highlight.start.row, annotation.highlight.start.column,
annotation.highlight.end.row, annotation.highlight.end.column
)
colorScheme: colorScheme
}
@_drawHighlight(annotation, colorScheme)
else if annotation.strikeThrough?
@labels.push {
text: annotation.label
range: new Range(
annotation.strikeThrough.start.row, annotation.strikeThrough.start.column,
annotation.strikeThrough.end.row, annotation.strikeThrough.end.column
)
colorScheme: colorScheme
}
@_drawStrikeThrough(annotation, colorScheme)
showAnnotationLabels: (position) ->
labelToShow = null
for label in @labels or []
if label.range.contains(position.row, position.column)
labelToShow = label
if !labelToShow?
@$scope.$apply () =>
@$scope.annotationLabel.show = false
else
$ace = $(@editor.renderer.container).find(".ace_scroller")
# Move the label into the Ace content area so that offsets and positions are easy to calculate.
$ace.append(@element.find(".annotation-label"))
if labelToShow.snapToStartOfRange
coords = @editor.renderer.textToScreenCoordinates(labelToShow.range.start.row, labelToShow.range.start.column)
else
coords = @editor.renderer.textToScreenCoordinates(position.row, position.column)
offset = $ace.offset()
height = $ace.height()
coords.pageX = coords.pageX - offset.left
coords.pageY = coords.pageY - offset.top
if coords.pageY > @editor.renderer.lineHeight * 2
top = "auto"
bottom = height - coords.pageY
else
top = coords.pageY + @editor.renderer.lineHeight
bottom = "auto"
# Apply this first that the label has the correct width when calculating below
@$scope.$apply () =>
@$scope.annotationLabel.text = labelToShow.text
@$scope.annotationLabel.show = true
$label = @element.find(".annotation-label")
console.log "pageX", coords.pageX, "label", $label.outerWidth(), "ace", $ace.width()
if coords.pageX + $label.outerWidth() < $ace.width()
left = coords.pageX
right = "auto"
else
right = 0
left = "auto"
@$scope.$apply () =>
@$scope.annotationLabel = {
show: true
left: left
right: right
bottom: bottom
top: top
backgroundColor: labelToShow.colorScheme.labelBackgroundColor
text: labelToShow.text
}
_clearMarkers: () ->
for marker_id in @markerIds
@editor.getSession().removeMarker(marker_id)
@markerIds = []
_clearLabels: () ->
@labels = []
_drawCursor: (annotation, colorScheme) ->
@markerIds.push @editor.getSession().addMarker new Range(
annotation.cursor.row, annotation.cursor.column,
annotation.cursor.row, annotation.cursor.column + 1
), "annotation remote-cursor", (html, range, left, top, config) ->
div = """
<div
class='remote-cursor custom ace_start'
style='height: #{config.lineHeight}px; top:#{top}px; left:#{left}px; border-color: #{colorScheme.cursor};'
>
<div class="nubbin" style="bottom: #{config.lineHeight}px; background-color: #{colorScheme.cursor};"></div>
</div>
"""
html.push div
, true
_drawHighlight: (annotation, colorScheme) ->
@_addMarkerWithCustomStyle(
new Range(
annotation.highlight.start.row, annotation.highlight.start.column,
annotation.highlight.end.row, annotation.highlight.end.column + 1
),
"annotation highlight",
false,
"background-color: #{colorScheme.highlightBackgroundColor}"
)
_drawStrikeThrough: (annotation, colorScheme) ->
lineHeight = @editor.renderer.lineHeight
@_addMarkerWithCustomStyle(
new Range(
annotation.strikeThrough.start.row, annotation.strikeThrough.start.column,
annotation.strikeThrough.end.row, annotation.strikeThrough.end.column + 1
),
"annotation strike-through-background",
false,
"background-color: #{colorScheme.strikeThroughBackgroundColor}"
)
@_addMarkerWithCustomStyle(
new Range(
annotation.strikeThrough.start.row, annotation.strikeThrough.start.column,
annotation.strikeThrough.end.row, annotation.strikeThrough.end.column + 1
),
"annotation strike-through-foreground",
true,
"""
height: #{Math.round(lineHeight/2) + 2}px;
border-bottom: 2px solid #{colorScheme.strikeThroughForegroundColor};
"""
)
_addMarkerWithCustomStyle: (range, klass, foreground, style) ->
if foreground?
markerLayer = @editor.renderer.$markerBack
else
markerLayer = @editor.renderer.$markerFront
@markerIds.push @editor.getSession().addMarker range, klass, (html, range, left, top, config) ->
if range.isMultiLine()
markerLayer.drawTextMarker(html, range, klass, config, style)
else
markerLayer.drawSingleLineMarker(html, range, "#{klass} ace_start", config, 0, style)
, foreground
_getColorScheme: (hue) ->
if @_isDarkTheme()
return {
cursor: "hsl(#{hue}, 100%, 50%)"
labelBackgroundColor: "hsl(#{hue}, 100%, 50%)"
highlightBackgroundColor: "hsl(#{hue}, 100%, 28%);"
strikeThroughBackgroundColor: "hsl(#{hue}, 100%, 20%);"
strikeThroughForegroundColor: "hsl(#{hue}, 100%, 60%);"
}
else
return {
cursor: "hsl(#{hue}, 100%, 50%)"
labelBackgroundColor: "hsl(#{hue}, 100%, 50%)"
highlightBackgroundColor: "hsl(#{hue}, 70%, 85%);"
strikeThroughBackgroundColor: "hsl(#{hue}, 70%, 95%);"
strikeThroughForegroundColor: "hsl(#{hue}, 70%, 40%);"
}
_isDarkTheme: () ->
rgb = @element.find(".ace_editor").css("background-color");
[m, r, g, b] = rgb.match(/rgb\(([0-9]+), ([0-9]+), ([0-9]+)\)/)
r = parseInt(r, 10)
g = parseInt(g, 10)
b = parseInt(b, 10)
return r + g + b < 3 * 128

View file

@ -88,6 +88,21 @@ define [
return null
findEntityByPath: (path) ->
@_findEntityByPathInFolder @$scope.rootFolder, path
_findEntityByPathInFolder: (folder, path) ->
parts = path.split("/")
name = parts.shift()
rest = parts.join("/")
for entity in folder.children
if entity.name == name
if rest == ""
return entity
else if entity.type == "folder"
return @_findEntityByPathInFolder(entity, rest)
return null
forEachEntity: (callback = (entity, parent_folder) ->) ->
@_forEachEntityInFolder(@$scope.rootFolder, callback)

View file

@ -4,7 +4,7 @@ define [
class OnlineUsersManager
constructor: (@ide, @$scope) ->
@$scope.onlineUsers = {}
@$scope.onlineUserCursorAnnotations = {}
@$scope.onlineUserCursorHighlights = {}
@$scope.$watch "editor.cursorPosition", (position) =>
if position?
@ -23,12 +23,12 @@ define [
updateCursorHighlights: () ->
console.log "UPDATING CURSOR HIGHLIGHTS"
@$scope.onlineUserCursorAnnotations = {}
@$scope.onlineUserCursorHighlights = {}
for client_id, client of @$scope.onlineUsers
doc_id = client.doc_id
continue if !doc_id?
@$scope.onlineUserCursorAnnotations[doc_id] ||= []
@$scope.onlineUserCursorAnnotations[doc_id].push {
@$scope.onlineUserCursorHighlights[doc_id] ||= []
@$scope.onlineUserCursorHighlights[doc_id].push {
label: client.name
cursor:
row: client.row

View file

@ -4,5 +4,15 @@ define [
], () ->
class PdfManager
constructor: (@ide, @$scope) ->
# All the logic actually happens in the controller
@$scope.pdf =
url: null # Pdf Url
error: false # Server error
timeout: false # Server timed out
failure: false # PDF failed to compile
compiling: false
uncompiled: true
logEntries: []
logEntryAnnotations: {}
rawLog: ""
view: null # 'pdf' 'logs'
showRawLog: false

View file

@ -3,18 +3,6 @@ define [
"libs/latex-log-parser"
], (App, LogParser) ->
App.controller "PdfController", ["$scope", "$http", "ide", "$modal", ($scope, $http, ide, $modal) ->
$scope.pdf =
url: null # Pdf Url
error: false # Server error
timeout: false # Server timed out
failure: false # PDF failed to compile
compiling: false
uncompiled: true
logEntries: []
rawLog: ""
view: null # 'pdf' 'logs'
showRawLog: false
autoCompile = true
$scope.$on "doc:opened", () ->
return if !autoCompile
@ -68,9 +56,21 @@ define [
logEntries = LogParser.parse(log, ignoreDuplicates: true)
$scope.pdf.logEntries = logEntries
$scope.pdf.logEntries.all = logEntries.errors.concat(logEntries.warnings).concat(logEntries.typesetting)
$scope.pdf.logEntryAnnotations = {}
for entry in logEntries.all
entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "")
entry.file = entry.file.replace(/^\/compile\//, "")
entity = ide.fileTreeManager.findEntityByPath(entry.file)
if entity?
$scope.pdf.logEntryAnnotations[entity.id] ||= []
$scope.pdf.logEntryAnnotations[entity.id].push {
row: entry.line - 1
type: if entry.level == "error" then "error" else "warning"
text: entry.message
}
.error () ->
$scope.pdf.logEntries = []
$scope.pdf.rawLog = ""
@ -131,6 +131,16 @@ define [
)
]
App.controller "PdfLogEntryController", ["$scope", "ide", ($scope, ide) ->
$scope.openInEditor = (entry) ->
console.log "OPENING", entry.file, entry.line
entity = ide.fileTreeManager.findEntityByPath(entry.file)
return if entity.type != "doc"
if entry.line?
line = entry.line - 1
ide.editorManager.openDoc(entity, gotoLine: line)
]
App.controller 'ClearCacheModalController', ["$scope", "$modalInstance", ($scope, $modalInstance) ->
$scope.state =
inflight: false

View file

@ -110,9 +110,9 @@ define [
.get(url)
.success (data) =>
diff.loading = false
{text, annotations} = @_parseDiff(data)
{text, highlights} = @_parseDiff(data)
diff.text = text
diff.annotations = annotations
diff.highlights = highlights
.error () ->
diff.loading = false
diff.error = true
@ -129,7 +129,7 @@ define [
_parseDiff: (diff) ->
row = 0
column = 0
annotations = []
highlights = []
text = ""
for entry, i in diff.diff or []
content = entry.u or entry.i or entry.d
@ -162,19 +162,19 @@ define [
name = "you"
date = moment(entry.meta.end_ts).format("Do MMM YYYY, h:mm a")
if entry.i?
annotations.push {
highlights.push {
label: "Added by #{name} on #{date}"
highlight: range
hue: @ide.onlineUsersManager.getHueForUserId(entry.meta.user.id)
}
else if entry.d?
annotations.push {
highlights.push {
label: "Deleted by #{name} on #{date}"
strikeThrough: range
hue: @ide.onlineUsersManager.getHueForUserId(entry.meta.user.id)
}
return {text, annotations}
return {text, highlights}
_loadUpdates: (updates = []) ->
previousUpdate = @$scope.trackChanges.updates[@$scope.trackChanges.updates.length - 1]

View file

@ -89,6 +89,7 @@
.alert {
font-size: 0.9rem;
margin-bottom: @line-height-computed / 2;
cursor: pointer;
.line-no {
float: right;
color: @gray;