Просмотр исходного кода

Jump to error when clicking on log entry

James Allen 12 лет назад
Родитель
Сommit
797dcf5c84

+ 4 - 2
services/web/app/views/project/editor/editor.jade

@@ -16,12 +16,14 @@ div.full-size(
 			font-size="settings.fontSize",
 			font-size="settings.fontSize",
 			auto-complete="settings.autoComplete",
 			auto-complete="settings.autoComplete",
 			spell-check-language="project.spellCheckLanguage",
 			spell-check-language="project.spellCheckLanguage",
-			annotations="onlineUserCursorAnnotations[editor.open_doc_id]"
+			highlights="onlineUserCursorHighlights[editor.open_doc_id]"
 			show-print-margin="false",
 			show-print-margin="false",
 			sharejs-doc="editor.sharejs_doc",
 			sharejs-doc="editor.sharejs_doc",
 			last-updated="editor.last_updated",
 			last-updated="editor.last_updated",
 			cursor-position="editor.cursorPosition",
 			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
 	.ui-layout-east

+ 2 - 1
services/web/app/views/project/editor/pdf.jade

@@ -59,13 +59,14 @@ div.full-size(ng-controller="PdfController")
 			strong Compile Error. 
 			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.
 			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(
 			.alert(
 				ng-class="{\
 				ng-class="{\
 					'alert-danger':  entry.level == 'error',\
 					'alert-danger':  entry.level == 'error',\
 					'alert-warning': entry.level == 'warning',\
 					'alert-warning': entry.level == 'warning',\
 					'alert-info':    entry.level == 'typesetting'\
 					'alert-info':    entry.level == 'typesetting'\
 				}"
 				}"
+				ng-click="openInEditor(entry)"
 			)
 			)
 				span.line-no
 				span.line-no
 					span(ng-show="entry.file") {{ entry.file }}
 					span(ng-show="entry.file") {{ entry.file }}

+ 1 - 1
services/web/app/views/project/editor/track-changes.jade

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

+ 11 - 4
services/web/public/coffee/app/ide/editor/EditorManager.coffee

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

+ 11 - 1
services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee

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

+ 17 - 4
services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee

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

+ 224 - 0
services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee

@@ -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

+ 15 - 0
services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee

@@ -88,6 +88,21 @@ define [
 
 
 			return null
 			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) ->) ->
 		forEachEntity: (callback = (entity, parent_folder) ->) ->
 			@_forEachEntityInFolder(@$scope.rootFolder, callback)
 			@_forEachEntityInFolder(@$scope.rootFolder, callback)
 
 

+ 4 - 4
services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee

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

+ 12 - 2
services/web/public/coffee/app/ide/pdf/PdfManager.coffee

@@ -4,5 +4,15 @@ define [
 ], () ->
 ], () ->
 	class PdfManager
 	class PdfManager
 		constructor: (@ide, @$scope) ->
 		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

+ 22 - 12
services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee

@@ -3,18 +3,6 @@ define [
 	"libs/latex-log-parser"
 	"libs/latex-log-parser"
 ], (App, LogParser) ->
 ], (App, LogParser) ->
 	App.controller "PdfController", ["$scope", "$http", "ide", "$modal", ($scope, $http, ide, $modal) ->
 	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
 		autoCompile = true
 		$scope.$on "doc:opened", () ->
 		$scope.$on "doc:opened", () ->
 			return if !autoCompile
 			return if !autoCompile
@@ -68,9 +56,21 @@ define [
 					logEntries = LogParser.parse(log, ignoreDuplicates: true)
 					logEntries = LogParser.parse(log, ignoreDuplicates: true)
 					$scope.pdf.logEntries = logEntries
 					$scope.pdf.logEntries = logEntries
 					$scope.pdf.logEntries.all = logEntries.errors.concat(logEntries.warnings).concat(logEntries.typesetting)
 					$scope.pdf.logEntries.all = logEntries.errors.concat(logEntries.warnings).concat(logEntries.typesetting)
+
+					$scope.pdf.logEntryAnnotations = {}
 					for entry in logEntries.all
 					for entry in logEntries.all
 						entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "")
 						entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "")
 						entry.file = entry.file.replace(/^\/compile\//, "")
 						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 () ->
 				.error () ->
 					$scope.pdf.logEntries = []
 					$scope.pdf.logEntries = []
 					$scope.pdf.rawLog = ""
 					$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) ->
 	App.controller 'ClearCacheModalController', ["$scope", "$modalInstance", ($scope, $modalInstance) ->
 		$scope.state =
 		$scope.state =
 			inflight: false
 			inflight: false

+ 6 - 6
services/web/public/coffee/app/ide/track-changes/TrackChangesManager.coffee

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

+ 1 - 0
services/web/public/stylesheets/app/editor/pdf.less

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